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. */