Commit 325d6b7d authored by Luca Burelli's avatar Luca Burelli Committed by Benjamin Cabé
Browse files

llext: add option to keep section data after llext_load



This is required for the functions that inspect the ELF file to work
properly. The user must then call llext_free_inspection_data() before
calling llext_unload() to free the memory left allocated in the loader
and extension memory.

Signed-off-by: default avatarLuca Burelli <l.burelli@arduino.cc>
parent 0201683a
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ static inline unsigned int llext_section_count(const struct llext *ext)
struct llext_load_param {
	/** Perform local relocation */
	bool relocate_local;

	/**
	 * Use the virtual symbol addresses from the ELF, not addresses within
	 * the memory buffer, when calculating relocation targets. It also
@@ -154,12 +155,22 @@ struct llext_load_param {
	 * allocation and copying internally.
	 */
	bool pre_located;

	/**
	 * Extensions can implement custom ELF sections to be loaded in specific
	 * memory regions, detached from other sections of compatible types.
	 * This optional callback checks whether a section should be detached.
	 */
	bool (*section_detached)(const elf_shdr_t *shdr);

	/**
	 * Keep the ELF section data in memory after loading the extension. This
	 * is needed to use some of the functions in @ref llext_inspect_apis.
	 *
	 * @note Related memory must be freed by @ref llext_free_inspection_data
	 *       before the extension can be unloaded via @ref llext_unload.
	 */
	bool keep_section_info;
};

/** Default initializer for @ref llext_load_param */
@@ -211,6 +222,19 @@ int llext_load(struct llext_loader *loader, const char *name, struct llext **ext
 */
int llext_unload(struct llext **ext);

/**
 * @brief Free any inspection-related memory for the specified loader and extension.
 *
 * This is only required if inspection data was requested at load time by
 * setting @ref llext_load_param.keep_section_info; otherwise, this call will
 * be a no-op.
 *
 * @param[in] ldr Extension loader
 * @param[in] ext Extension
 * @returns 0 on success, or a negative error code.
 */
int llext_free_inspection_data(struct llext_loader *ldr, struct llext *ext);

/** @brief Entry point function signature for an extension. */
typedef void (*llext_entry_fn_t)(void *user_data);

+17 −4
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ static int llext_load_elf_data(struct llext_loader *ldr, struct llext *ext)
		LOG_ERR("Failed to allocate section map, size %zu", sect_map_sz);
		return -ENOMEM;
	}
	ext->alloc_size += sect_map_sz;
	for (int i = 0; i < ext->sect_cnt; i++) {
		ldr->sect_map[i].mem_idx = LLEXT_MEM_COUNT;
		ldr->sect_map[i].offset = 0;
@@ -759,12 +760,13 @@ int do_llext_load(struct llext_loader *ldr, struct llext *ext,

out:
	/*
	 * Free resources only used during loading. Note that this exploits
	 * the fact that freeing a NULL pointer has no effect.
	 * Free resources only used during loading, unless explicitly requested.
	 * Note that this exploits the fact that freeing a NULL pointer has no effect.
	 */

	llext_free(ldr->sect_map);
	ldr->sect_map = NULL;
	if (ret != 0 || !ldr_parm || !ldr_parm->keep_section_info) {
		llext_free_inspection_data(ldr, ext);
	}

	/* Until proper inter-llext linking is implemented, the symbol table is
	 * not useful outside of the loading process; keep it only if debugging
@@ -796,3 +798,14 @@ out:

	return ret;
}

int llext_free_inspection_data(struct llext_loader *ldr, struct llext *ext)
{
	if (ldr->sect_map) {
		ext->alloc_size -= ext->sect_cnt * sizeof(ldr->sect_map[0]);
		llext_free(ldr->sect_map);
		ldr->sect_map = NULL;
	}

	return 0;
}