From 52c99cb1d59a5221b2467aa9ddd9b68c8fc1e8b1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Apr 2024 14:32:32 +0200 Subject: [PATCH 1/6] llext: avoid copying 32KiB of meaningless data We're skipping unused 0x8000 bytes of data at the beginning of the module, so we have to reduce the amount of data to be copied accordingly. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 2f0afb6ddbe5..78169aebb783 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -142,6 +142,7 @@ static void __sparse_cache *llext_manager_get_bss_address(uint32_t module_id, static int llext_manager_allocate_module_bss(uint32_t module_id, const struct sof_man_module *mod) { + /* FIXME: just map .bss together with .data and simply memset(.bss, 0) */ struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); size_t bss_size = ctx->segment_size[SOF_MAN_SEGMENT_BSS]; void __sparse_cache *va_base = llext_manager_get_bss_address(module_id, mod); @@ -170,7 +171,7 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul uint32_t module_id, struct module_data *md, const void **buildinfo, const struct sof_man_module_manifest **mod_manifest) { - size_t mod_size = desc->header.preload_page_count * PAGE_SZ; + size_t mod_size = desc->header.preload_page_count * PAGE_SZ - 0x8000; /* FIXME: where does the module begin?? */ struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)desc - SOF_MAN_ELF_TEXT_OFFSET + 0x8000, From 3ab3003be7f89125b619f0f492f3e02e523504f3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Apr 2024 15:13:36 +0200 Subject: [PATCH 2/6] llext: use data size from Zephyr Some image formats, notably relocatable objects, don't create ELF segments. To work around this use the object data size, calculated by Zephyr. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 78169aebb783..77ac5624a130 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -200,8 +200,7 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul mod->segment[SOF_MAN_SEGMENT_RODATA].file_offset = (uintptr_t)md->llext->mem[LLEXT_MEM_RODATA] - (uintptr_t)desc + SOF_MAN_ELF_TEXT_OFFSET; - ctx->segment_size[SOF_MAN_SEGMENT_RODATA] = mod_size - - ebl.loader.sects[LLEXT_MEM_TEXT].sh_size; + ctx->segment_size[SOF_MAN_SEGMENT_RODATA] = ebl.loader.prog_data_size; tr_dbg(&lib_manager_tr, ".data: start: %#x size %#x offset %#x", mod->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr, From 546abcc065bf3f35af7a3baa60e767260a4ee80a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Apr 2024 15:16:03 +0200 Subject: [PATCH 3/6] llext: check whether the first instance is initialised We need to tell Zephyr whether or not to perform local relocations. Check persistent library data to distinguish the first instantiation from the following ones. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/lib_manager.c | 2 +- src/library_manager/llext_manager.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index e01fb154634f..fc3726df6e6a 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -471,7 +471,7 @@ static void lib_manager_update_sof_ctx(void *base_addr, uint32_t lib_id) { struct ext_library *_ext_lib = ext_lib_get(); /* Never freed, will panic if fails */ - struct lib_manager_mod_ctx *ctx = rmalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, + struct lib_manager_mod_ctx *ctx = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(*ctx)); ctx->base_addr = base_addr; diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 77ac5624a130..64b90c3eefd6 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -176,8 +176,9 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)desc - SOF_MAN_ELF_TEXT_OFFSET + 0x8000, mod_size); - struct llext_load_param ldr_parm = {false}; struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); + /* Identify if this is the first time loading this module */ + struct llext_load_param ldr_parm = {!ctx->segment_size[SOF_MAN_SEGMENT_TEXT]}; int ret = llext_load(&ebl.loader, mod->name, &md->llext, &ldr_parm); if (ret < 0) From 1c5a7cd275de237719c677e5b5333331142775ab Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Apr 2024 15:21:15 +0200 Subject: [PATCH 4/6] llext: add support for building relocatable modules Add support for relocatable objects to the llext module build system. In such builds no ELF segments are created, so we need to process all sections individually. Signed-off-by: Guennadi Liakhovetski --- scripts/llext_link_helper.py | 56 +++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/scripts/llext_link_helper.py b/scripts/llext_link_helper.py index 1b8ad8c86221..cfd3d5205fec 100755 --- a/scripts/llext_link_helper.py +++ b/scripts/llext_link_helper.py @@ -7,9 +7,11 @@ # portable way to do that. Therefore we pass the linker path and all the command # line parameters to this script and call the linker directly. +import os import argparse import subprocess from elftools.elf.elffile import ELFFile +import re args = None def parse_args(): @@ -33,21 +35,53 @@ def main(): elf = ELFFile(open(args.file, 'rb')) text_addr = int(args.text_addr, 0) + p = re.compile('(^lib|\.so$)') + module = p.sub('', args.file) - text_offset = elf.get_section_by_name('.text').header.sh_offset - rodata_offset = elf.get_section_by_name('.rodata').header.sh_offset - data_offset = elf.get_section_by_name('.data').header.sh_offset + if elf.num_segments() != 0: + # A shared object type image, it contains segments + sections = ['.text', '.rodata', '.data', '.bss'] + alignment = [0x1000, 0x1000, 0x10, 0x1000] + else: + # A relocatable object, need to handle all sections separately + sections = ['.text', + f'._log_const.static.log_const_{module}_', + '.static_uuids', '.z_init_APPLICATION90_0_', '.module', + '.mod_buildinfo', '.data', '.trace_ctx', '.bss'] + alignment = [0x1000, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x1000] - upper = rodata_offset - text_offset + text_addr + 0xfff - rodata_addr = upper - (upper % 0x1000) + last_increment = 0 - upper = data_offset - rodata_offset + rodata_addr + 0xf - data_addr = upper - (upper % 0x10) + command = [args.command] + + for i in range(len(sections)): + try: + offset = elf.get_section_by_name(sections[i]).header.sh_offset + size = elf.get_section_by_name(sections[i]).header.sh_size + except: + continue + + if last_increment == 0: + # first section must be .text and it must be successful + if i != 0 or sections[i] != '.text': + break + + address = text_addr + elif alignment[i] != 0: + upper = offset + last_increment + alignment[i] - 1 + address = upper - (upper % alignment[i]) + else: + address = offset + last_increment + + last_increment = address - offset + + if sections[i] == '.text': + command.append(f'-Wl,-Ttext=0x{text_addr:x}') + elif sections[i] == '.data': + command.append(f'-Wl,-Tdata=0x{address:x}') + else: + command.append(f'-Wl,--section-start={sections[i]}=0x{address:x}') - command = [args.command, - f'-Wl,-Ttext=0x{text_addr:x}', - f'-Wl,--section-start=.rodata=0x{rodata_addr:x}', - f'-Wl,-Tdata=0x{data_addr:x}'] command.extend(args.params) subprocess.run(command) From 2948bb4c497fbf898eb9f67cb094718144a5b795 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Apr 2024 16:21:05 +0200 Subject: [PATCH 5/6] rimage: add support for relocatable objects Relocatable ELF objects don't contain segments, update rimage to prevent it from aborting in such cases. Signed-off-by: Guennadi Liakhovetski --- tools/rimage/src/elf_file.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tools/rimage/src/elf_file.c b/tools/rimage/src/elf_file.c index 7415a35c228a..991766d45062 100644 --- a/tools/rimage/src/elf_file.c +++ b/tools/rimage/src/elf_file.c @@ -132,15 +132,6 @@ static int elf_header_read(struct elf_file *elf) if (elf->header.ehsize < sizeof(Elf32_Ehdr)) return elf_error(elf, "Invalid file header size.", EINVAL); - if (elf->header.phoff >= elf->file_size) - return elf_error(elf, "Invalid program header file offset.", EINVAL); - - if (elf->header.phentsize < sizeof(Elf32_Phdr)) - return elf_error(elf, "Invalid program header size.", EINVAL); - - if (elf->header.phoff + elf->header.phnum * sizeof(Elf32_Phdr) > elf->file_size) - return elf_error(elf, "Invalid number of program header entries.", EINVAL); - if (elf->header.shoff >= elf->file_size) return elf_error(elf, "Invalid section header file offset.", EINVAL); @@ -250,6 +241,12 @@ static int elf_program_headers_read(struct elf_file *elf) int i, ret; size_t offset, count; + if (!elf->header.phnum) { + elf->programs = NULL; + elf->programs_count = 0; + return 0; + } + elf->programs = calloc(elf->header.phnum, sizeof(Elf32_Phdr)); if (!elf->programs) return elf_error(elf, "Cannot allocate program array.", ENOMEM); From 7d01cd4e8546d2e561237647664d5a557184904b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Apr 2024 16:40:33 +0200 Subject: [PATCH 6/6] smart-amp-test: add support for the Cadence toolchain The Cadence Xtensa cross-toolchain cannot build shared libraries, when using it we build relocatable ELF objects instead. Update smart-amp-test to support both formats. Signed-off-by: Guennadi Liakhovetski --- src/samples/audio/smart_amp_llext/CMakeLists.txt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/samples/audio/smart_amp_llext/CMakeLists.txt b/src/samples/audio/smart_amp_llext/CMakeLists.txt index ded003b1ecb3..2e57380bf65b 100644 --- a/src/samples/audio/smart_amp_llext/CMakeLists.txt +++ b/src/samples/audio/smart_amp_llext/CMakeLists.txt @@ -53,7 +53,16 @@ target_compile_options(${MODULE} PRIVATE -save-temps -O2 ) +if("${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "zephyr") set(MODULE_LINKER_PARAMS -nostdlib -nodefaultlibs) +set(EXTRA_LINKED_PARAMS -shared) +set(COPY_CMD ${CMAKE_STRIP} -R .xt.* -o ${MODULE}_out.so ${MODULE}_llext.so) +else() +set(MODULE_LINKER_PARAMS -nostdlib -nodefaultlibs -r) +set(EXTRA_LINKED_PARAMS) +set(COPY_CMD ${CMAKE_OBJCOPY} -R .xt.* ${MODULE}_llext.so ${MODULE}_out.so) +endif() + target_link_options(${MODULE} PRIVATE ${MODULE_LINKER_PARAMS} ) @@ -62,9 +71,9 @@ add_custom_command(OUTPUT lib${MODULE}_out.so DEPENDS ${MODULE} COMMAND ${SOF_BASE}scripts/llext_link_helper.py -f lib${MODULE}.so -t "0xa06ca000" ${CMAKE_C_COMPILER} -- - ${MODULE_LINKER_PARAMS} -shared -fPIC - -o lib${MODULE}_llext.so $ - COMMAND ${CMAKE_STRIP} -R .xt.* -o lib${MODULE}_out.so lib${MODULE}_llext.so + ${MODULE_LINKER_PARAMS} ${EXTRA_LINKED_PARAMS} -fPIC + -o ${MODULE}_llext.so $ + COMMAND ${COPY_CMD} COMMAND_EXPAND_LISTS )