diff --git a/.gitignore b/.gitignore
index 4b79ea81ca7e2cefcebee447196fb824eb739fe7..e3a98180f6a523e8ba0aaec289f98f646e96ba3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
 *.bin
 *.fae
 *.elf
+build
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000000000000000000000000000000000000..7eea02fb3905722b88510cf3d7389a5f09816559
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Gilles Grimaud <gilles.grimaud@univ-lille.fr>
+Damien Amara <damien.amara@univ-lille.fr>
+Gregory Guche <gregory.guche@univ-lille.fr>
diff --git a/Makefile b/Makefile
index c0ee0f5e014bf5f79dc3a7e598475c7a8f38f490..ad0e4ae1002d8143e0573c6c2bc882f99b254240 100644
--- a/Makefile
+++ b/Makefile
@@ -45,65 +45,31 @@ ifeq ($(shell $(PREFIX)ld --help | grep -q 'warn-rwx-segments'; echo $$?), 0)
 LDFLAGS        += -Wl,--no-warn-rwx-segments
 endif
 
-OBJCOPYFLAGS    = --input-target=elf32-littlearm
-OBJCOPYFLAGS   += --output-target=binary
 
 TARGET          = hello-world
 
-all: $(TARGET).fae gdbinit
+all: build/$(TARGET).fae
 
-$(TARGET).fae: $(TARGET)-raw.fae padding.fae
-	cat $^ > $@
+build :
+	mkdir -p build
 
-$(TARGET)-raw.fae: crt0.fae symbols.fae relocation.fae partition.fae
-	cat $^ > $@
+build/$(TARGET).fae: build/$(TARGET).elf
+	./fae_utils/build_fae.py $<
 
-crt0.fae: crt0/crt0.c crt0/link.ld crt0/Makefile
-	make -C crt0 realclean all
-	cp crt0/$@ $@
-
-symbols.fae: $(TARGET).elf scripts/symbols.py
-	exec scripts/symbols.py $< $@
-
-relocation.fae: $(TARGET).elf scripts/relocation.py
-	exec scripts/relocation.py $< $@
-
-partition.fae: $(TARGET).elf
-	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
-	@chmod 644 $@
-
-$(TARGET).elf: main.o stdriot/stdriot.o
+build/$(TARGET).elf: build/main.o build/stdriot.o
 	$(LD) $(LDFLAGS) $^ -o $@
 
-stdriot/stdriot.o: stdriot/stdriot.c
+build/stdriot.o: stdriot/stdriot.c | build
 	$(CC) $(CFLAGS) -c $< -o $@
 
-main.o: main.c
+build/main.o: main.c | build
 	$(CC) $(CFLAGS) -c $< -o $@
 
-padding.fae: $(TARGET)-raw.fae scripts/padding.py
-	exec scripts/padding.py $< $@
-
-gdbinit: scripts/gdbinit.py crt0/crt0.elf $(TARGET).fae crt0.fae symbols.fae relocation.fae
-	exec scripts/gdbinit.py\
-            $(shell realpath crt0/crt0.elf)\
-            $(shell realpath $(TARGET).elf)\
-            $$(($$(wc -c < crt0.fae)+$$(wc -c < symbols.fae)+$$(wc -c < relocation.fae))) > $@
-
 clean:
-	$(RM)\
-            main.o\
-            stdriot/stdriot.o\
-            $(TARGET)-raw.fae\
-            padding.fae\
-            crt0.fae\
-            symbols.fae\
-            relocation.fae\
-            partition.fae
+	$(RM) build/main.o build/stdriot.o
 	make -C crt0 clean
 
 realclean: clean
-	$(RM) $(TARGET).elf $(TARGET).fae gdbinit
-	make -C crt0 realclean
+	$(RM) -rf build
 
 .PHONY: all clean realclean
diff --git a/crt0/Makefile b/crt0/Makefile
index ed18e6fca0945230a64fae462f1b92c30490e3be..716429037c45e0ebebf5bbe41139655bab5facca 100644
--- a/crt0/Makefile
+++ b/crt0/Makefile
@@ -51,24 +51,27 @@ CFLAGS   += -Os
 CFLAGS   += -g3
 CFLAGS   += -ggdb
 
-all: crt0.fae
+all: ../build/crt0.fae
 
-crt0.fae: crt0.elf
+../build:
+	mkdir -p ../build
+
+../build/crt0.fae: ../build/crt0.elf
 	$(OBJCOPY)\
           --input-target=elf32-littlearm\
           --output-target=binary\
         $< $@
 
-crt0.elf: crt0.o
+../build/crt0.elf: ../build/crt0.o
 	$(LD) -T link.ld $< -o $@
 
-crt0.o: crt0.c
+../build/crt0.o: crt0.c | ../build
 	$(CC) $(CFLAGS) -c $< -o $@
 
 realclean: clean
-	$(RM) -f crt0.elf crt0.bin
+	$(RM) -f ../build/crt0.fae ../build/crt0.elf
 
 clean:
-	$(RM) -f crt0.o
+	$(RM) -f ../build/crt0.o
 
 .PHONY: all realclean clean
diff --git a/crt0/crt0.c b/crt0/crt0.c
index e7faebd7c5fb050896f816f735ef711bc496c811..410ecf3fa44faedb4cc617bba47787adb2d96f4a 100644
--- a/crt0/crt0.c
+++ b/crt0/crt0.c
@@ -227,9 +227,7 @@ _start(interface_t *interface, void **syscalls)
 	interface->unusedRamStart =
 		(void *)(relRamSecAddr + ramSecSize);
 	/* Update of the unused ROM value. */
-	/* XXX bad unusedRomStart... */
-	interface->unusedRomStart =
-		(void *)((uintptr_t)interface->unusedRomStart + ((uint32_t)&__metadataOff) + sizeof(metadata_t) + metadata->symbolTable.romRamEnd);
+	interface->unusedRomStart = (void *)relRomRamSecAddr + romRamSecSize;
 
 	/* Relocation of the '.rom.ram' section. */
 	(void)memcpy((void *) relRomRamSecAddr,
diff --git a/fae_utils/build_fae.py b/fae_utils/build_fae.py
new file mode 100755
index 0000000000000000000000000000000000000000..10bb1931a12d8046c9c4ed1440786e37d29687f2
--- /dev/null
+++ b/fae_utils/build_fae.py
@@ -0,0 +1,281 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2025 Université de Lille
+#
+# This file is subject to the terms and conditions of the GNU Lesser
+# General Public License v2.1. See the file LICENSE in the top level
+# directory for more details.
+
+import os
+import sys
+import subprocess
+
+from elftools.elf.elffile import ELFFile
+from elftools.elf.sections import SymbolTableSection
+from elftools.elf.relocation import RelocationSection
+from elftools.elf.enums import ENUM_RELOC_TYPE_ARM as r_types
+
+FAE_SUFFIX      = ".fae"
+CRTO_CLI_OPTION = "--crt0_path"
+EXPORT_CRT0_TO_BYTEARRAY_DEFAULT_PATH = "./crt0/"
+
+def usage():
+    """Print how to to use the script and exit"""
+    print(f'usage: {sys.argv[0]} [{CRTO_CLI_OPTION} crt0_path] ELFFilename')
+    print('')
+    print(f'{sys.argv[0]} will build :')
+    print(f'    - a fae file from ELFFilename,')
+    print(f'    - a gdbinit file, to be used with gdb after editing.')
+    print(f'Please note that both files will be generated to the path of ELFFilename.')
+    print('')
+    print(f'{CRTO_CLI_OPTION} crt0_path')
+    print(f'    This option allows to indicate a path to a custom crt0')
+    print(f'    Default is {EXPORT_CRT0_TO_BYTEARRAY_DEFAULT_PATH}')
+    sys.exit(1)
+
+
+def die(message):
+    """Print error message and exit"""
+    print(f'\033[91;1m{sys.argv[0]}: {message}\033[0m', file=sys.stderr)
+    sys.exit(1)
+
+
+def export_crt0_to_bytearray(path_to_crt0, to_bytearray):
+    make_args = f"make -C {os.path.abspath(path_to_crt0)} realclean all"
+
+    result = subprocess.run(make_args, shell=True, capture_output=True, text=True)
+    if result.returncode != 0:
+        die(f'export_crt0_to_bytearray : failed to build crt0 : {result.stderr}')
+
+    crt0_filepath = path_to_crt0 + "/crt0.fae"
+    with open(crt0_filepath, "rb") as crt0_file:
+        to_bytearray += bytearray(crt0_file.read())
+
+def to_word(x):
+    """Convert a python integer to a LE 4-bytes bytearray"""
+    return x.to_bytes(4, byteorder='little')
+
+EXPORTED_SYMBOLS = [
+    # The order of the symbols matter, as it reflects the
+    # writing order in the symbols.bin file
+    'start',
+    '__rom_size',
+    '__rom_ram_size',
+    '__ram_size',
+    '__got_size',
+    '__rom_ram_end',
+]
+
+def export_symbols_to_bytearray(elf_file, symbols_names, to_bytearray):
+    """Parse the symbol table sections to extract the st_value"""
+    sh = elf_file.get_section_by_name('.symtab')
+    if not sh:
+        die(f'export_symbols_to_bytearray : .symtab : no section with this name found')
+    if not isinstance(sh, SymbolTableSection):
+        die(f'export_symbols_to_bytearray : .symtab : is not a symbol table section')
+    if sh['sh_type'] != 'SHT_SYMTAB':
+        die(f'export_symbols_to_bytearray : .symtab : is not a SHT_SYMTAB section')
+    for symbol_name in symbols_names:
+        symbols = sh.get_symbol_by_name(symbol_name)
+        if not symbols:
+            die(f'export_symbols_to_bytearray : .symtab : {symbol_name}: no symbol with this name')
+        if len(symbols) > 1:
+            die(f'export_symbols_to_bytearray : .symtab : {symbol_name}: more than one symbol with this name')
+        to_bytearray += to_word(symbols[0].entry['st_value'])
+
+
+EXPORTED_RELOCATION_TABLES = [ '.rel.rom.ram' ]
+
+def get_r_type(r_info):
+    """Get the relocation type from r_info"""
+    return r_info & 0xff
+
+def export_relocation_table(elf_file, relocation_table_name, to_bytearray):
+    """Parse a relocation section to extract the r_offset"""
+    sh = elf_file.get_section_by_name(relocation_table_name)
+    if not sh:
+        die(f'export_relocation_table : {relocation_table_name}: is not a relocation section')
+    if not isinstance(sh, RelocationSection):
+        die(f'export_relocation_table : {relocation_table_name}: is not a relocation section')
+    if sh.is_RELA():
+        die(f'export_relocation_table : {relocation_table_name} : unsupported RELA')
+    to_bytearray += to_word(sh.num_relocations())
+    for i, entry in enumerate(sh.iter_relocations()):
+        if get_r_type(entry['r_info']) != r_types['R_ARM_ABS32']:
+            die(f'export_relocation_table : {relocation_table_name} : entry {i}: unsupported relocation type')
+        to_bytearray += to_word(entry['r_offset'])
+
+def export_relocation_tables(elf_file, relocation_tables_names, to_bytearray):
+    for relocation_table_name in relocation_tables_names:
+        export_relocation_table(elf_file, relocation_table_name, to_bytearray)
+
+
+EXPORT_PARTITION_OBJCOPY_DEFAULT_NAME = "arm-none-eabi-objcopy"
+
+EXPORT_PARTITION_OBJCOPY_FLAGS = [
+    "--input-target=elf32-littlearm", "--output-target=binary"
+]
+
+def export_partition(elf_name, objcopy_name, objcopy_flags, to_bytearray):
+    partition_name = "partition.fae"
+
+    objcopy_args = objcopy_name
+    for objcopy_flag in objcopy_flags:
+        objcopy_args += f' {objcopy_flag}'
+    objcopy_args += f' {elf_name} {partition_name}'
+
+    result = subprocess.run(objcopy_args, shell=True, capture_output=True, text=True)
+    if result.returncode != 0:
+        print(f'export_partition : {result.stdout}')
+        die(f'export_partition : failed to run objcopy : {result.stderr}')
+
+    with open(partition_name, "rb") as partition_file:
+        to_bytearray += bytearray(partition_file.read())
+
+    rm_args = f'rm {partition_name}'
+
+    result = subprocess.run(args=rm_args, shell=True, capture_output=True, text=True)
+    if result.returncode != 0:
+        die(f'export_partition : failed to remove {partition_name} : {result.stderr}')
+
+
+# The default value used for padding. This value corresponds to
+# the default state of non-volatile NAND flash memories
+PADDING_VALUE = b'\xff'
+
+
+# The Pip binary size must be a multiple of this value. It
+# corresponds to the minimum alignment required by the MPU of
+# the ARMv7-M architecture
+PADDING_MPU_ALIGNMENT = 32
+
+def round(x, y):
+    """Round x to the next power of two y"""
+    return ((x + y - 1) & ~(y - 1))
+
+def pad_bytearray(to_bytearray):
+    size = len(to_bytearray)
+    padding = round(size, PADDING_MPU_ALIGNMENT) - size
+    for i in range(padding):
+        to_bytearray += PADDING_VALUE
+
+
+GENERATE_GDBINIT_DEFAULT_SYMBOLS_TO_FIND = [
+    '__rom_size',
+    '__got_size',
+    '__rom_ram_size',
+    '__ram_size',
+]
+
+def gdbinit_find_symbols(elf_file, symbols_to_find):
+    """Parse the symbol table sections to extract the st_value"""
+    sh = elf_file.get_section_by_name('.symtab')
+    if not sh:
+        die(f'gdbinit_find_symbols : .symtab : no section with this name found')
+    if not isinstance(sh, SymbolTableSection):
+        die(f'gdbinit_find_symbols : .symtab : is not a symbol table section')
+    if sh['sh_type'] != 'SHT_SYMTAB':
+        die(f'gdbinit_find_symbols : .symtab : is not a SHT_SYMTAB section')
+    found_symbols = []
+    for symbol_name in symbols_to_find:
+        symbols = sh.get_symbol_by_name(symbol_name)
+        if not symbols:
+            die(f'gdbinit_find_symbols : .symtab : {symbol_name}: no symbol with this name')
+        if len(symbols) > 1:
+            die(f'gdbinit_find_symbols : .symtab : {symbol_name}: more than one symbol with this name')
+        found_symbols.append(symbols[0].entry['st_value'])
+    return found_symbols
+
+def generate_gdbinit(elf_file, crt0_path, metadata_size):
+    found_symbols = gdbinit_find_symbols(elf_file, GENERATE_GDBINIT_DEFAULT_SYMBOLS_TO_FIND)
+
+    text_size = found_symbols[0]
+    got_size  = found_symbols[1]
+    data_size = found_symbols[2]
+    bss_size  = found_symbols[3]
+
+    basepath           = elf_file.stream.name.split("/")[0]
+    absolute_elf_path  = os.path.abspath(elf_file.stream.name)
+    absolute_crt0_path = os.path.abspath(crt0_path + "crt0.elf")
+
+    with open(f"{basepath}/gdbinit", "w+") as gdbinit_file:
+        gdbinit_file.write(f'set $flash_base = # Define the flash base address here\n')
+        gdbinit_file.write(f'set $ram_base = # Define the RAM base address here\n')
+        gdbinit_file.write(f'set $crt0_text = $flash_base\n')
+        gdbinit_file.write(f'set $text = $crt0_text + {metadata_size}\n')
+        gdbinit_file.write(f'set $got = $text + {text_size}\n')
+        gdbinit_file.write(f'set $data = $got + {got_size}\n')
+        gdbinit_file.write(f'set $rel_got = $ram_base\n')
+        gdbinit_file.write(f'set $rel_data = $rel_got + {got_size}\n')
+        gdbinit_file.write(f'set $bss = $rel_data + {data_size}\n')
+        gdbinit_file.write(f'add-symbol-file {absolute_crt0_path} -s .text $crt0_text\n')
+        gdbinit_file.write(f'add-symbol-file {absolute_elf_path} '
+                           '-s .rom $text '
+                           '-s .got $rel_got '
+                           '-s .rom.ram $rel_data '
+                           '-s .ram $bss\n')
+        gdbinit_file.write('set $flash_end = $flash_base + '
+                           f'{metadata_size + text_size + got_size + data_size}\n')
+        gdbinit_file.write(f'set $ram_end = $ram_base + {got_size + data_size + bss_size}\n')
+
+
+if __name__ == '__main__':
+    argc = len(sys.argv)
+    if argc != 2 and argc != 4:
+        print(f"argc {argc}")
+        usage()
+
+
+
+    if argc == 2:
+        elf_filename = sys.argv[1].strip()
+        crt0_path = EXPORT_CRT0_TO_BYTEARRAY_DEFAULT_PATH.strip()
+    else :
+        if (sys.argv[1] != CRTO_CLI_OPTION):
+            usage()
+
+        crt0_path = sys.argv[2].strip()
+        elf_filename = sys.argv[3].strip()
+
+    elf_filename_parts = elf_filename.split('.')
+    if len(elf_filename_parts) != 2 or elf_filename_parts[1] != 'elf':
+        print('Bad ELFFilename : should be something along the line of name.elf')
+        usage()
+
+    output_filename = elf_filename_parts[0] + FAE_SUFFIX
+
+    if crt0_path.endswith('/') == False:
+        crt0_path += '/'
+
+    array_of_bytes = bytearray()
+    with open(elf_filename, 'rb') as f:
+        elf_file = ELFFile(f)
+
+        # Formerly known as crt0.fae
+        export_crt0_to_bytearray(crt0_path, array_of_bytes)
+
+        # Formerly known as symbols.fae
+        export_symbols_to_bytearray(elf_file, EXPORTED_SYMBOLS, array_of_bytes)
+
+        # Formerly known as relocation.fae
+        export_relocation_tables(elf_file, EXPORTED_RELOCATION_TABLES, array_of_bytes)
+        metadata_size = len(array_of_bytes)
+
+        # Formerly known as partition.fae
+        export_partition(
+            elf_filename,
+            EXPORT_PARTITION_OBJCOPY_DEFAULT_NAME,
+            EXPORT_PARTITION_OBJCOPY_FLAGS,
+            array_of_bytes)
+
+        #Formerly known as padding.fae
+        pad_bytearray(array_of_bytes)
+
+        # gdbinit
+        generate_gdbinit( elf_file, crt0_path, metadata_size )
+
+    if (len(array_of_bytes) <= 0):
+        die("Nothing has been written into array_of_bytes ! Please contact authors.")
+    with open(output_filename, 'wb') as f:
+        f.write(array_of_bytes)
+    sys.exit(0)
diff --git a/scripts/gdbinit.py b/fae_utils/gdbinit.py
similarity index 100%
rename from scripts/gdbinit.py
rename to fae_utils/gdbinit.py
diff --git a/scripts/padding.py b/fae_utils/padding.py
similarity index 100%
rename from scripts/padding.py
rename to fae_utils/padding.py
diff --git a/scripts/relocation.py b/fae_utils/relocation.py
similarity index 100%
rename from scripts/relocation.py
rename to fae_utils/relocation.py
diff --git a/scripts/requirements.txt b/fae_utils/requirements.txt
similarity index 100%
rename from scripts/requirements.txt
rename to fae_utils/requirements.txt
diff --git a/scripts/symbols.py b/fae_utils/symbols.py
similarity index 100%
rename from scripts/symbols.py
rename to fae_utils/symbols.py
diff --git a/main.c b/main.c
index 1438bdb51213c36b5ff17412064b0c8b955c2163..c3f2dad4812a6f900c1a7e76d4862e8a04a6f411 100644
--- a/main.c
+++ b/main.c
@@ -37,15 +37,14 @@ const int cst = 3;
 
 int main(int argc, char **argv)
 {
-    /*
     int i;
-
+/*
     printf("Hello World!\n");
-
+*/
     for (i = 1; i < argc; i++) {
-        printf("%s\n", argv[i]);
+        printf("arg %d : %s\n", i, argv[i]);
     }
-    */
+
 
     if (argc > 1) {
         func_ptr_extern_1 = func_b;
diff --git a/stdriot/stdriot.h b/stdriot/stdriot.h
index 2963a9ef19a8143ed49f290ca7759944208cfa05..2008cd986b66a3bc6a1b9e1b442ff97edd37e336 100644
--- a/stdriot/stdriot.h
+++ b/stdriot/stdriot.h
@@ -1,5 +1,5 @@
 /*******************************************************************************/
-/*  © Université de Lille, The Pip Development Team (2015-2024)                */
+/*  © Université de Lille, The Pip Development Team (2015-2025)                */
 /*                                                                             */
 /*  This software is a computer program whose purpose is to run a minimal,     */
 /*  hypervisor relying on proven properties such as memory isolation.          */