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) 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 2f0afb6ddbe5..64b90c3eefd6 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,13 +171,14 @@ 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, 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) @@ -199,8 +201,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, 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 ) 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);