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