Skip to content
Snippets Groups Projects
Commit bff723a3 authored by Gregory Guche's avatar Gregory Guche
Browse files

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.
parent 176e201f
Branches
No related tags found
No related merge requests found
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
*.bin *.bin
*.fae *.fae
*.elf *.elf
build
Gilles Grimaud <gilles.grimaud@univ-lille.fr>
Damien Amara <damien.amara@univ-lille.fr>
Gregory Guche <gregory.guche@univ-lille.fr>
...@@ -45,65 +45,31 @@ ifeq ($(shell $(PREFIX)ld --help | grep -q 'warn-rwx-segments'; echo $$?), 0) ...@@ -45,65 +45,31 @@ ifeq ($(shell $(PREFIX)ld --help | grep -q 'warn-rwx-segments'; echo $$?), 0)
LDFLAGS += -Wl,--no-warn-rwx-segments LDFLAGS += -Wl,--no-warn-rwx-segments
endif endif
OBJCOPYFLAGS = --input-target=elf32-littlearm
OBJCOPYFLAGS += --output-target=binary
TARGET = hello-world TARGET = hello-world
all: $(TARGET).fae gdbinit all: build/$(TARGET).fae
$(TARGET).fae: $(TARGET)-raw.fae padding.fae build :
cat $^ > $@ mkdir -p build
$(TARGET)-raw.fae: crt0.fae symbols.fae relocation.fae partition.fae build/$(TARGET).fae: build/$(TARGET).elf
cat $^ > $@ ./fae_utils/build_fae.py $<
crt0.fae: crt0/crt0.c crt0/link.ld crt0/Makefile build/$(TARGET).elf: build/main.o build/stdriot.o
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
$(LD) $(LDFLAGS) $^ -o $@ $(LD) $(LDFLAGS) $^ -o $@
stdriot/stdriot.o: stdriot/stdriot.c build/stdriot.o: stdriot/stdriot.c | build
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
main.o: main.c build/main.o: main.c | build
$(CC) $(CFLAGS) -c $< -o $@ $(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: clean:
$(RM)\ $(RM) build/main.o build/stdriot.o
main.o\
stdriot/stdriot.o\
$(TARGET)-raw.fae\
padding.fae\
crt0.fae\
symbols.fae\
relocation.fae\
partition.fae
make -C crt0 clean make -C crt0 clean
realclean: clean realclean: clean
$(RM) $(TARGET).elf $(TARGET).fae gdbinit $(RM) -rf build
make -C crt0 realclean
.PHONY: all clean realclean .PHONY: all clean realclean
...@@ -51,24 +51,27 @@ CFLAGS += -Os ...@@ -51,24 +51,27 @@ CFLAGS += -Os
CFLAGS += -g3 CFLAGS += -g3
CFLAGS += -ggdb CFLAGS += -ggdb
all: crt0.fae all: ../build/crt0.fae
crt0.fae: crt0.elf ../build:
mkdir -p ../build
../build/crt0.fae: ../build/crt0.elf
$(OBJCOPY)\ $(OBJCOPY)\
--input-target=elf32-littlearm\ --input-target=elf32-littlearm\
--output-target=binary\ --output-target=binary\
$< $@ $< $@
crt0.elf: crt0.o ../build/crt0.elf: ../build/crt0.o
$(LD) -T link.ld $< -o $@ $(LD) -T link.ld $< -o $@
crt0.o: crt0.c ../build/crt0.o: crt0.c | ../build
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
realclean: clean realclean: clean
$(RM) -f crt0.elf crt0.bin $(RM) -f ../build/crt0.fae ../build/crt0.elf
clean: clean:
$(RM) -f crt0.o $(RM) -f ../build/crt0.o
.PHONY: all realclean clean .PHONY: all realclean clean
...@@ -227,9 +227,7 @@ _start(interface_t *interface, void **syscalls) ...@@ -227,9 +227,7 @@ _start(interface_t *interface, void **syscalls)
interface->unusedRamStart = interface->unusedRamStart =
(void *)(relRamSecAddr + ramSecSize); (void *)(relRamSecAddr + ramSecSize);
/* Update of the unused ROM value. */ /* Update of the unused ROM value. */
/* XXX bad unusedRomStart... */ interface->unusedRomStart = (void *)relRomRamSecAddr + romRamSecSize;
interface->unusedRomStart =
(void *)((uintptr_t)interface->unusedRomStart + ((uint32_t)&__metadataOff) + sizeof(metadata_t) + metadata->symbolTable.romRamEnd);
/* Relocation of the '.rom.ram' section. */ /* Relocation of the '.rom.ram' section. */
(void)memcpy((void *) relRomRamSecAddr, (void)memcpy((void *) relRomRamSecAddr,
......
#!/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)
File moved
File moved
File moved
File moved
File moved
...@@ -37,15 +37,14 @@ const int cst = 3; ...@@ -37,15 +37,14 @@ const int cst = 3;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
/*
int i; int i;
/*
printf("Hello World!\n"); printf("Hello World!\n");
*/
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
printf("%s\n", argv[i]); printf("arg %d : %s\n", i, argv[i]);
} }
*/
if (argc > 1) { if (argc > 1) {
func_ptr_extern_1 = func_b; func_ptr_extern_1 = func_b;
......
/*******************************************************************************/ /*******************************************************************************/
/* © 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, */ /* This software is a computer program whose purpose is to run a minimal, */
/* hypervisor relying on proven properties such as memory isolation. */ /* hypervisor relying on proven properties such as memory isolation. */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment