From bff723a38ecf9b8be20d74bcf1e8ac579939540c Mon Sep 17 00:00:00 2001 From: Gregory Guche <gregory.guche@univ-lille.fr> Date: Thu, 10 Apr 2025 16:17:16 +0200 Subject: [PATCH] Changed FAE file generation from Makefiles/Python to an unique Python file FAE file generation was previously handled by different Python scripts and their result was concatenated thanks to Makefiles. Now, FAE file generation is handled by a sole Python script and Makefiles have been modified accordinly. A build folder has been added and is managed automatically by Makefiles. This directory has been added to the gitignore file. --- .gitignore | 1 + AUTHORS | 3 + Makefile | 54 +---- crt0/Makefile | 15 +- crt0/crt0.c | 4 +- fae_utils/build_fae.py | 281 ++++++++++++++++++++++++ {scripts => fae_utils}/gdbinit.py | 0 {scripts => fae_utils}/padding.py | 0 {scripts => fae_utils}/relocation.py | 0 {scripts => fae_utils}/requirements.txt | 0 {scripts => fae_utils}/symbols.py | 0 main.c | 9 +- stdriot/stdriot.h | 2 +- 13 files changed, 310 insertions(+), 59 deletions(-) create mode 100644 AUTHORS create mode 100755 fae_utils/build_fae.py rename {scripts => fae_utils}/gdbinit.py (100%) rename {scripts => fae_utils}/padding.py (100%) rename {scripts => fae_utils}/relocation.py (100%) rename {scripts => fae_utils}/requirements.txt (100%) rename {scripts => fae_utils}/symbols.py (100%) diff --git a/.gitignore b/.gitignore index 4b79ea8..e3a9818 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.bin *.fae *.elf +build diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..7eea02f --- /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 c0ee0f5..ad0e4ae 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 ed18e6f..7164290 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 e7faebd..410ecf3 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 0000000..10bb193 --- /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 1438bdb..c3f2dad 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 2963a9e..2008cd9 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. */ -- GitLab