Commit 2255b638 authored by Eric Ackermann's avatar Eric Ackermann Committed by Carles Cufi
Browse files

llext: Refactor symbol lookup logic into function



This commit refactors logic in llext_link.c that resolves
a symbol to be imported by an llext into a utility function.
Thereby, the logic can be re-used in other functions if
needed, e.g., when resolving symbols for indirect relocations.

Signed-off-by: default avatarEric Ackermann <eric.ackermann@cispa.de>
parent d0a1945f
Loading
Loading
Loading
Loading
+83 −57
Original line number Diff line number Diff line
@@ -142,6 +142,84 @@ static const void *llext_find_extension_sym(const char *sym_name, struct llext *
	return se.addr;
}

/**
 * @brief Determine address of a symbol.
 *
 * @param ext llext extension
 * @param ldr llext loader
 * @param link_addr (output) resolved address
 * @param rel relocation entry
 * @param sym symbol entry
 * @param name symbol name
 * @param shdr section header
 *
 * @return 0 for OK, negative for error
 */
static int llext_lookup_symbol(struct llext *ext, struct llext_loader *ldr, uintptr_t *link_addr,
			       const elf_rela_t *rel, const elf_sym_t *sym, const char *name,
			       const elf_shdr_t *shdr)
{
	if (ELF_R_SYM(rel->r_info) == 0) {
		/*
		 * no symbol
		 * example:  R_ARM_V4BX relocation, R_ARM_RELATIVE
		 */
		*link_addr = 0;
	} else if (sym->st_shndx == SHN_UNDEF) {
		/* If symbol is undefined, then we need to look it up */
		*link_addr = (uintptr_t)llext_find_sym(NULL, SYM_NAME_OR_SLID(name, sym->st_value));

		if (*link_addr == 0) {
			/* Try loaded tables */
			struct llext *dep;

			*link_addr = (uintptr_t)llext_find_extension_sym(name, &dep);
			if (*link_addr) {
				llext_dependency_add(ext, dep);
			}
		}

		if (*link_addr == 0) {
			LOG_ERR("Undefined symbol with no entry in "
				"symbol table %s, offset %zd, link section %d",
				name, (size_t)rel->r_offset, shdr->sh_link);
			return -ENODATA;
		}

		LOG_INF("found symbol %s at 0x%lx", name, *link_addr);
	} else if (sym->st_shndx == SHN_ABS) {
		/* Absolute symbol */
		*link_addr = sym->st_value;
	} else if ((sym->st_shndx < ldr->hdr.e_shnum) &&
		   !IN_RANGE(sym->st_shndx, SHN_LORESERVE, SHN_HIRESERVE)) {
		/* This check rejects all relocations whose target symbol has a section index higher
		 * than the maximum possible in this ELF file, or belongs in the reserved range:
		 * they will be caught by the `else` below and cause an error to be returned. This
		 * aborts the LLEXT's loading and prevents execution of improperly relocated code,
		 * which is dangerous.
		 *
		 * Note that the unsupported SHN_COMMON section is rejected as part of this check.
		 * Also note that SHN_ABS would be rejected as well, but we want to handle it
		 * properly: for this reason, this check must come AFTER handling the case where the
		 * symbol's section index is SHN_ABS!
		 *
		 *
		 * For regular symbols, the link address is obtained by adding st_value to the start
		 * address of the section in which the target symbol resides.
		 */
		*link_addr =
			(uintptr_t)llext_loaded_sect_ptr(ldr, ext, sym->st_shndx) + sym->st_value;
	} else {
		LOG_ERR("cannot apply relocation: "
			"target symbol has unexpected section index %d (0x%X)",
			sym->st_shndx, sym->st_shndx);
		return -ENOEXEC;
	}

	return 0;
}


static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr,
			   const struct llext_load_param *ldr_parm, elf_shdr_t *tgt)
{
@@ -407,64 +485,12 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_l

			op_loc = sect_base + rel.r_offset;

			if (ELF_R_SYM(rel.r_info) == 0) {
				/* no symbol ex: R_ARM_V4BX relocation, R_ARM_RELATIVE  */
				link_addr = 0;
			} else if (sym.st_shndx == SHN_UNDEF) {
				/* If symbol is undefined, then we need to look it up */
				link_addr = (uintptr_t)llext_find_sym(NULL,
					SYM_NAME_OR_SLID(name, sym.st_value));

				if (link_addr == 0) {
					/* Try loaded tables */
					struct llext *dep;

					link_addr = (uintptr_t)llext_find_extension_sym(name, &dep);
					if (link_addr) {
						llext_dependency_add(ext, dep);
					}
				}

				if (link_addr == 0) {
					LOG_ERR("Undefined symbol with no entry in "
						"symbol table %s, offset %zd, link section %d",
						name, (size_t)rel.r_offset, shdr->sh_link);
					return -ENODATA;
				}
			ret = llext_lookup_symbol(ext, ldr, &link_addr, &rel, &sym, name, shdr);

				LOG_INF("found symbol %s at 0x%lx", name, link_addr);
			} else if (sym.st_shndx == SHN_ABS) {
				/* Absolute symbol */
				link_addr = sym.st_value;
			} else if ((sym.st_shndx < ldr->hdr.e_shnum) &&
				!IN_RANGE(sym.st_shndx, SHN_LORESERVE, SHN_HIRESERVE)) {
				/* This check rejects all relocations whose target symbol
				 * has a section index higher than the maximum possible
				 * in this ELF file, or belongs in the reserved range:
				 * they will be caught by the `else` below and cause an
				 * error to be returned. This aborts the LLEXT's loading
				 * and prevents execution of improperly relocated code,
				 * which is dangerous.
				 *
				 * Note that the unsupported SHN_COMMON section is rejected
				 * as part of this check. Also note that SHN_ABS would be
				 * rejected as well, but we want to handle it properly:
				 * for this reason, this check must come AFTER handling
				 * the case where the symbol's section index is SHN_ABS!
				 *
				 *
				 * For regular symbols, the link address is obtained by
				 * adding st_value to the start address of the section
				 * in which the target symbol resides.
				 */
				link_addr = (uintptr_t)llext_loaded_sect_ptr(ldr, ext,
									     sym.st_shndx)
					    + sym.st_value;
			} else {
				LOG_ERR("rela section %d, entry %d: cannot apply relocation: "
					"target symbol has unexpected section index %d (0x%X)",
					i, j, sym.st_shndx, sym.st_shndx);
				return -ENOEXEC;
			if (ret != 0) {
				LOG_ERR("Failed to lookup symbol in rela section %d entry %d!", i,
					j);
				return ret;
			}

			LOG_INF("writing relocation symbol %s type %zd sym %zd at addr 0x%lx "