xref: /optee_os/ldelf/ta_elf_rel.c (revision c44d734b6366cbf4d12610310e809872db65f89d)
17509ff7cSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
27509ff7cSJens Wiklander /*
37509ff7cSJens Wiklander  * Copyright (c) 2019, Linaro Limited
47509ff7cSJens Wiklander  */
57509ff7cSJens Wiklander 
67509ff7cSJens Wiklander #include <assert.h>
75548a710SJerome Forissier #include <compiler.h>
855e64090SJens Wiklander #include <confine_array_index.h>
97509ff7cSJens Wiklander #include <elf32.h>
107509ff7cSJens Wiklander #include <elf64.h>
117509ff7cSJens Wiklander #include <elf_common.h>
127509ff7cSJens Wiklander #include <string.h>
137509ff7cSJens Wiklander #include <tee_api_types.h>
147509ff7cSJens Wiklander #include <util.h>
157509ff7cSJens Wiklander 
167509ff7cSJens Wiklander #include "sys.h"
177509ff7cSJens Wiklander #include "ta_elf.h"
187509ff7cSJens Wiklander 
199f392760SJerome Forissier static uint32_t elf_hash(const char *name)
209f392760SJerome Forissier {
219f392760SJerome Forissier 	const unsigned char *p = (const unsigned char *)name;
229f392760SJerome Forissier 	uint32_t h = 0;
239f392760SJerome Forissier 	uint32_t g = 0;
249f392760SJerome Forissier 
259f392760SJerome Forissier 	while (*p) {
269f392760SJerome Forissier 		h = (h << 4) + *p++;
279f392760SJerome Forissier 		g = h & 0xf0000000;
289f392760SJerome Forissier 		if (g)
299f392760SJerome Forissier 			h ^= g >> 24;
309f392760SJerome Forissier 		h &= ~g;
319f392760SJerome Forissier 	}
329f392760SJerome Forissier 	return h;
339f392760SJerome Forissier }
349f392760SJerome Forissier 
3597c5ac19SJens Wiklander static bool __resolve_sym(struct ta_elf *elf, unsigned int st_bind,
3697c5ac19SJens Wiklander 			  unsigned int st_type, size_t st_shndx,
3797c5ac19SJens Wiklander 			  size_t st_name, size_t st_value, const char *name,
38cf830b2bSJerome Forissier 			  vaddr_t *val, bool weak_ok)
397509ff7cSJens Wiklander {
40cf830b2bSJerome Forissier 	bool bind_ok = false;
41cf830b2bSJerome Forissier 
427509ff7cSJens Wiklander 	if (!st_name)
437509ff7cSJens Wiklander 		return false;
447509ff7cSJens Wiklander 	if (st_name > elf->dynstr_size)
4597c5ac19SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol name out of range");
467509ff7cSJens Wiklander 	if (strcmp(name, elf->dynstr + st_name))
477509ff7cSJens Wiklander 		return false;
48cf830b2bSJerome Forissier 	if (st_bind == STB_GLOBAL || (weak_ok && st_bind == STB_WEAK))
49cf830b2bSJerome Forissier 		bind_ok = true;
50cf830b2bSJerome Forissier 	if (!bind_ok)
51cf830b2bSJerome Forissier 		return false;
52cf830b2bSJerome Forissier 	if (st_bind == STB_WEAK && st_shndx == SHN_UNDEF) {
53cf830b2bSJerome Forissier 		if (val)
54cf830b2bSJerome Forissier 			*val = 0;
55cf830b2bSJerome Forissier 		return true;
56cf830b2bSJerome Forissier 	}
57cf830b2bSJerome Forissier 	if (st_shndx == SHN_UNDEF || st_shndx == SHN_XINDEX)
58cf830b2bSJerome Forissier 		return false;
597509ff7cSJens Wiklander 
6097c5ac19SJens Wiklander 	switch (st_type) {
61bb8cd6f0SJerome Forissier 	case STT_NOTYPE:
6297c5ac19SJens Wiklander 	case STT_OBJECT:
6397c5ac19SJens Wiklander 	case STT_FUNC:
64c88ba125SJerome Forissier 		if (st_value > (elf->max_addr - elf->load_addr))
65c88ba125SJerome Forissier 			err(TEE_ERROR_BAD_FORMAT,
66c88ba125SJerome Forissier 			    "Symbol location out of range");
67c88ba125SJerome Forissier 		if (val)
687509ff7cSJens Wiklander 			*val = st_value + elf->load_addr;
6997c5ac19SJens Wiklander 		break;
70c88ba125SJerome Forissier 	case STT_TLS:
71c88ba125SJerome Forissier 		if (val)
72c88ba125SJerome Forissier 			*val = st_value;
73c88ba125SJerome Forissier 		break;
7497c5ac19SJens Wiklander 	default:
7597c5ac19SJens Wiklander 		err(TEE_ERROR_NOT_SUPPORTED, "Symbol type not supported");
7697c5ac19SJens Wiklander 	}
7797c5ac19SJens Wiklander 
787509ff7cSJens Wiklander 	return true;
797509ff7cSJens Wiklander }
807509ff7cSJens Wiklander 
81ebef121cSJerome Forissier static TEE_Result resolve_sym_helper(uint32_t hash, const char *name,
82cf830b2bSJerome Forissier 				     vaddr_t *val, struct ta_elf *elf,
83cf830b2bSJerome Forissier 				     bool weak_ok)
847509ff7cSJens Wiklander {
859f392760SJerome Forissier 	/*
869f392760SJerome Forissier 	 * Using uint32_t here for convenience because both Elf64_Word
879f392760SJerome Forissier 	 * and Elf32_Word are 32-bit types
889f392760SJerome Forissier 	 */
899f392760SJerome Forissier 	uint32_t *hashtab = elf->hashtab;
909f392760SJerome Forissier 	uint32_t nbuckets = hashtab[0];
919f392760SJerome Forissier 	uint32_t nchains = hashtab[1];
929f392760SJerome Forissier 	uint32_t *bucket = &hashtab[2];
939f392760SJerome Forissier 	uint32_t *chain = &bucket[nbuckets];
94ebef121cSJerome Forissier 	size_t n = 0;
959f392760SJerome Forissier 
967509ff7cSJens Wiklander 	if (elf->is_32bit) {
977509ff7cSJens Wiklander 		Elf32_Sym *sym = elf->dynsymtab;
987509ff7cSJens Wiklander 
999f392760SJerome Forissier 		for (n = bucket[hash % nbuckets]; n; n = chain[n]) {
1008dbe2cbdSJens Wiklander 			if (n >= nchains || n >= elf->num_dynsyms)
1015c0860dbSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
1025c0860dbSJens Wiklander 				    "Index out of range");
10355e64090SJens Wiklander 			/*
10455e64090SJens Wiklander 			 * We're loading values from sym[] which later
10555e64090SJens Wiklander 			 * will be used to load something.
10655e64090SJens Wiklander 			 * => Spectre V1 pattern, need to cap the index
10755e64090SJens Wiklander 			 * against speculation.
10855e64090SJens Wiklander 			 */
10955e64090SJens Wiklander 			n = confine_array_index(n, elf->num_dynsyms);
1107509ff7cSJens Wiklander 			if (__resolve_sym(elf,
1117509ff7cSJens Wiklander 					  ELF32_ST_BIND(sym[n].st_info),
11297c5ac19SJens Wiklander 					  ELF32_ST_TYPE(sym[n].st_info),
1137509ff7cSJens Wiklander 					  sym[n].st_shndx,
1147509ff7cSJens Wiklander 					  sym[n].st_name,
115cf830b2bSJerome Forissier 					  sym[n].st_value, name, val, weak_ok))
116c86f218cSJens Wiklander 				return TEE_SUCCESS;
1177509ff7cSJens Wiklander 		}
1187509ff7cSJens Wiklander 	} else {
1197509ff7cSJens Wiklander 		Elf64_Sym *sym = elf->dynsymtab;
1207509ff7cSJens Wiklander 
1219f392760SJerome Forissier 		for (n = bucket[hash % nbuckets]; n; n = chain[n]) {
1228dbe2cbdSJens Wiklander 			if (n >= nchains || n >= elf->num_dynsyms)
1235c0860dbSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
1245c0860dbSJens Wiklander 				    "Index out of range");
12555e64090SJens Wiklander 			/*
12655e64090SJens Wiklander 			 * We're loading values from sym[] which later
12755e64090SJens Wiklander 			 * will be used to load something.
12855e64090SJens Wiklander 			 * => Spectre V1 pattern, need to cap the index
12955e64090SJens Wiklander 			 * against speculation.
13055e64090SJens Wiklander 			 */
13155e64090SJens Wiklander 			n = confine_array_index(n, elf->num_dynsyms);
1327509ff7cSJens Wiklander 			if (__resolve_sym(elf,
1337509ff7cSJens Wiklander 					  ELF64_ST_BIND(sym[n].st_info),
13497c5ac19SJens Wiklander 					  ELF64_ST_TYPE(sym[n].st_info),
1357509ff7cSJens Wiklander 					  sym[n].st_shndx,
1367509ff7cSJens Wiklander 					  sym[n].st_name,
137cf830b2bSJerome Forissier 					  sym[n].st_value, name, val, weak_ok))
138c86f218cSJens Wiklander 				return TEE_SUCCESS;
1397509ff7cSJens Wiklander 		}
1407509ff7cSJens Wiklander 	}
141ebef121cSJerome Forissier 
142ebef121cSJerome Forissier 	return TEE_ERROR_ITEM_NOT_FOUND;
1437509ff7cSJens Wiklander }
144c86f218cSJens Wiklander 
145cf830b2bSJerome Forissier /*
146cf830b2bSJerome Forissier  * Look for named symbol in @elf, or all modules if @elf == NULL. Global symbols
147cf830b2bSJerome Forissier  * are searched first, then weak ones. Last option, when at least one weak but
148cf830b2bSJerome Forissier  * undefined symbol exists, resolve to zero. Otherwise return
149cf830b2bSJerome Forissier  * TEE_ERROR_ITEM_NOT_FOUND.
150c88ba125SJerome Forissier  * @val (if != 0) receives the symbol value
151c88ba125SJerome Forissier  * @found_elf (if != 0) receives the module where the symbol is found
152cf830b2bSJerome Forissier  */
153ebef121cSJerome Forissier TEE_Result ta_elf_resolve_sym(const char *name, vaddr_t *val,
154c88ba125SJerome Forissier 			      struct ta_elf **found_elf,
155ebef121cSJerome Forissier 			      struct ta_elf *elf)
156ebef121cSJerome Forissier {
157ebef121cSJerome Forissier 	uint32_t hash = elf_hash(name);
158ebef121cSJerome Forissier 
159cf830b2bSJerome Forissier 	if (elf) {
160cf830b2bSJerome Forissier 		/* Search global symbols */
161cf830b2bSJerome Forissier 		if (!resolve_sym_helper(hash, name, val, elf,
162cf830b2bSJerome Forissier 					false /* !weak_ok */))
163c88ba125SJerome Forissier 			goto success;
164cf830b2bSJerome Forissier 		/* Search weak symbols */
165cf830b2bSJerome Forissier 		if (!resolve_sym_helper(hash, name, val, elf,
166cf830b2bSJerome Forissier 					true /* weak_ok */))
167c88ba125SJerome Forissier 			goto success;
168cf830b2bSJerome Forissier 	}
169cf830b2bSJerome Forissier 
170cf830b2bSJerome Forissier 	TAILQ_FOREACH(elf, &main_elf_queue, link) {
171cf830b2bSJerome Forissier 		if (!resolve_sym_helper(hash, name, val, elf,
172cf830b2bSJerome Forissier 					false /* !weak_ok */))
173c88ba125SJerome Forissier 			goto success;
174cf830b2bSJerome Forissier 		if (!resolve_sym_helper(hash, name, val, elf,
175cf830b2bSJerome Forissier 					true /* weak_ok */))
176c88ba125SJerome Forissier 			goto success;
177cf830b2bSJerome Forissier 	}
178ebef121cSJerome Forissier 
179c86f218cSJens Wiklander 	return TEE_ERROR_ITEM_NOT_FOUND;
180c88ba125SJerome Forissier 
181c88ba125SJerome Forissier success:
182c88ba125SJerome Forissier 	if (found_elf)
183c88ba125SJerome Forissier 		*found_elf = elf;
184c88ba125SJerome Forissier 	return TEE_SUCCESS;
185c86f218cSJens Wiklander }
186c86f218cSJens Wiklander 
187c88ba125SJerome Forissier static void e32_get_sym_name(const Elf32_Sym *sym_tab, size_t num_syms,
1887509ff7cSJens Wiklander 			     const char *str_tab, size_t str_tab_size,
189*c44d734bSJerome Forissier 			     Elf32_Rel *rel, const char **name,
190*c44d734bSJerome Forissier 			     bool *weak_undef)
1917509ff7cSJens Wiklander {
1927509ff7cSJens Wiklander 	size_t sym_idx = 0;
1937509ff7cSJens Wiklander 	size_t name_idx = 0;
1947509ff7cSJens Wiklander 
1957509ff7cSJens Wiklander 	sym_idx = ELF32_R_SYM(rel->r_info);
196447354c6SJens Wiklander 	if (sym_idx >= num_syms)
197e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range");
19855e64090SJens Wiklander 	sym_idx = confine_array_index(sym_idx, num_syms);
1997509ff7cSJens Wiklander 
2007509ff7cSJens Wiklander 	name_idx = sym_tab[sym_idx].st_name;
201447354c6SJens Wiklander 	if (name_idx >= str_tab_size)
202e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Name index out of range");
203c88ba125SJerome Forissier 	*name = str_tab + name_idx;
204*c44d734bSJerome Forissier 
205*c44d734bSJerome Forissier 	if (!weak_undef)
206*c44d734bSJerome Forissier 		return;
207*c44d734bSJerome Forissier 	if (sym_tab[sym_idx].st_shndx == SHN_UNDEF &&
208*c44d734bSJerome Forissier 	    ELF32_ST_BIND(sym_tab[sym_idx].st_info) == STB_WEAK)
209*c44d734bSJerome Forissier 		*weak_undef = true;
210*c44d734bSJerome Forissier 	else
211*c44d734bSJerome Forissier 		*weak_undef = false;
212c88ba125SJerome Forissier }
2137509ff7cSJens Wiklander 
214*c44d734bSJerome Forissier static void resolve_sym(const char *name, vaddr_t *val, struct ta_elf **mod,
215*c44d734bSJerome Forissier 			bool err_if_not_found)
216c88ba125SJerome Forissier {
217c88ba125SJerome Forissier 	TEE_Result res = ta_elf_resolve_sym(name, val, mod, NULL);
218c88ba125SJerome Forissier 
219*c44d734bSJerome Forissier 	if (res) {
220*c44d734bSJerome Forissier 		if (err_if_not_found)
221c88ba125SJerome Forissier 			err(res, "Symbol %s not found", name);
222*c44d734bSJerome Forissier 		else
223*c44d734bSJerome Forissier 			*val = 0;
224*c44d734bSJerome Forissier 	}
225c88ba125SJerome Forissier }
226c88ba125SJerome Forissier 
227c88ba125SJerome Forissier static void e32_process_dyn_rel(const Elf32_Sym *sym_tab, size_t num_syms,
228c88ba125SJerome Forissier 				const char *str_tab, size_t str_tab_size,
229c88ba125SJerome Forissier 				Elf32_Rel *rel, Elf32_Addr *where)
230c88ba125SJerome Forissier {
231c88ba125SJerome Forissier 	const char *name = NULL;
232c88ba125SJerome Forissier 	vaddr_t val = 0;
233*c44d734bSJerome Forissier 	bool weak_undef = false;
234c88ba125SJerome Forissier 
235*c44d734bSJerome Forissier 	e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name,
236*c44d734bSJerome Forissier 			 &weak_undef);
237*c44d734bSJerome Forissier 	resolve_sym(name, &val, NULL, !weak_undef);
2387509ff7cSJens Wiklander 	*where = val;
2397509ff7cSJens Wiklander }
2407509ff7cSJens Wiklander 
241c88ba125SJerome Forissier static void e32_tls_get_module(const Elf32_Sym *sym_tab, size_t num_syms,
242c88ba125SJerome Forissier 			       const char *str_tab, size_t str_tab_size,
243c88ba125SJerome Forissier 			       Elf32_Rel *rel, struct ta_elf **mod)
244c88ba125SJerome Forissier {
245c88ba125SJerome Forissier 	const char *name = NULL;
246c88ba125SJerome Forissier 	size_t sym_idx = 0;
247c88ba125SJerome Forissier 
248c88ba125SJerome Forissier 	sym_idx = ELF32_R_SYM(rel->r_info);
249c88ba125SJerome Forissier 	if (sym_idx >= num_syms)
250c88ba125SJerome Forissier 		err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range");
251c88ba125SJerome Forissier 	sym_idx = confine_array_index(sym_idx, num_syms);
252c88ba125SJerome Forissier 	if (!sym_idx || sym_tab[sym_idx].st_shndx != SHN_UNDEF) {
253c88ba125SJerome Forissier 		/* No symbol, or symbol is defined in current module */
254c88ba125SJerome Forissier 		return;
255c88ba125SJerome Forissier 	}
256c88ba125SJerome Forissier 
257*c44d734bSJerome Forissier 	e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name,
258*c44d734bSJerome Forissier 			 NULL);
259*c44d734bSJerome Forissier 	resolve_sym(name, NULL, mod, false);
260c88ba125SJerome Forissier }
261c88ba125SJerome Forissier 
262c88ba125SJerome Forissier static void e32_tls_resolve(const Elf32_Sym *sym_tab, size_t num_syms,
263c88ba125SJerome Forissier 			    const char *str_tab, size_t str_tab_size,
264c88ba125SJerome Forissier 			    Elf32_Rel *rel, vaddr_t *val)
265c88ba125SJerome Forissier {
266c88ba125SJerome Forissier 	const char *name = NULL;
267c88ba125SJerome Forissier 
268*c44d734bSJerome Forissier 	e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name,
269*c44d734bSJerome Forissier 			 NULL);
270*c44d734bSJerome Forissier 	resolve_sym(name, val, NULL, false);
271c88ba125SJerome Forissier }
272c88ba125SJerome Forissier 
2737509ff7cSJens Wiklander static void e32_relocate(struct ta_elf *elf, unsigned int rel_sidx)
2747509ff7cSJens Wiklander {
2757509ff7cSJens Wiklander 	Elf32_Shdr *shdr = elf->shdr;
2767509ff7cSJens Wiklander 	Elf32_Rel *rel = NULL;
2777509ff7cSJens Wiklander 	Elf32_Rel *rel_end = NULL;
2787509ff7cSJens Wiklander 	size_t sym_tab_idx = 0;
2797509ff7cSJens Wiklander 	Elf32_Sym *sym_tab = NULL;
2807509ff7cSJens Wiklander 	size_t num_syms = 0;
2817509ff7cSJens Wiklander 	size_t sh_end = 0;
2827509ff7cSJens Wiklander 	const char *str_tab = NULL;
2837509ff7cSJens Wiklander 	size_t str_tab_size = 0;
2847509ff7cSJens Wiklander 
2857509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_type == SHT_REL);
2867509ff7cSJens Wiklander 
2877509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_entsize == sizeof(Elf32_Rel));
2887509ff7cSJens Wiklander 
2897509ff7cSJens Wiklander 	sym_tab_idx = shdr[rel_sidx].sh_link;
2907509ff7cSJens Wiklander 	if (sym_tab_idx) {
2917509ff7cSJens Wiklander 		size_t str_tab_idx = 0;
2927509ff7cSJens Wiklander 
293447354c6SJens Wiklander 		if (sym_tab_idx >= elf->e_shnum)
294dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB index out of range");
29555e64090SJens Wiklander 		sym_tab_idx = confine_array_index(sym_tab_idx, elf->e_shnum);
2967509ff7cSJens Wiklander 
2977509ff7cSJens Wiklander 		assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf32_Sym));
2987509ff7cSJens Wiklander 
2997509ff7cSJens Wiklander 		/* Check the address is inside ELF memory */
3007509ff7cSJens Wiklander 		if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr,
3017509ff7cSJens Wiklander 				 shdr[sym_tab_idx].sh_size, &sh_end))
302e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Overflow");
303447354c6SJens Wiklander 		if (sh_end >= (elf->max_addr - elf->load_addr))
304dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB out of range");
3057509ff7cSJens Wiklander 
3067509ff7cSJens Wiklander 		sym_tab = (Elf32_Sym *)(elf->load_addr +
3077509ff7cSJens Wiklander 					shdr[sym_tab_idx].sh_addr);
3087509ff7cSJens Wiklander 
3097509ff7cSJens Wiklander 		num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf32_Sym);
3107509ff7cSJens Wiklander 
3117509ff7cSJens Wiklander 		str_tab_idx = shdr[sym_tab_idx].sh_link;
3127509ff7cSJens Wiklander 		if (str_tab_idx) {
31355e64090SJens Wiklander 			if (str_tab_idx >= elf->e_shnum)
314e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
315dcf64f87SJens Wiklander 				    "STRTAB index out of range");
31655e64090SJens Wiklander 			str_tab_idx = confine_array_index(str_tab_idx,
31755e64090SJens Wiklander 							  elf->e_shnum);
31855e64090SJens Wiklander 
3197509ff7cSJens Wiklander 			/* Check the address is inside ELF memory */
3207509ff7cSJens Wiklander 			if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr,
3217509ff7cSJens Wiklander 					 shdr[str_tab_idx].sh_size, &sh_end))
322e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT, "Overflow");
323447354c6SJens Wiklander 			if (sh_end >= (elf->max_addr - elf->load_addr))
324e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
325dcf64f87SJens Wiklander 				    "STRTAB out of range");
3267509ff7cSJens Wiklander 
3277509ff7cSJens Wiklander 			str_tab = (const char *)(elf->load_addr +
3287509ff7cSJens Wiklander 						 shdr[str_tab_idx].sh_addr);
3297509ff7cSJens Wiklander 			str_tab_size = shdr[str_tab_idx].sh_size;
3307509ff7cSJens Wiklander 		}
3317509ff7cSJens Wiklander 	}
3327509ff7cSJens Wiklander 
3337509ff7cSJens Wiklander 	/* Check the address is inside TA memory */
334447354c6SJens Wiklander 	if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr,
335447354c6SJens Wiklander 			 shdr[rel_sidx].sh_size, &sh_end))
336e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Overflow");
337447354c6SJens Wiklander 	if (sh_end >= (elf->max_addr - elf->load_addr))
338dcf64f87SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, ".rel.*/REL out of range");
3397509ff7cSJens Wiklander 	rel = (Elf32_Rel *)(elf->load_addr + shdr[rel_sidx].sh_addr);
3407509ff7cSJens Wiklander 
3417509ff7cSJens Wiklander 	rel_end = rel + shdr[rel_sidx].sh_size / sizeof(Elf32_Rel);
3427509ff7cSJens Wiklander 	for (; rel < rel_end; rel++) {
343c88ba125SJerome Forissier 		struct ta_elf *mod = NULL;
3447509ff7cSJens Wiklander 		Elf32_Addr *where = NULL;
3457509ff7cSJens Wiklander 		size_t sym_idx = 0;
346c88ba125SJerome Forissier 		vaddr_t val = 0;
3477509ff7cSJens Wiklander 
3487509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
349447354c6SJens Wiklander 		if (rel->r_offset >= (elf->max_addr - elf->load_addr))
350e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT,
351447354c6SJens Wiklander 			    "Relocation offset out of range");
3527509ff7cSJens Wiklander 		where = (Elf32_Addr *)(elf->load_addr + rel->r_offset);
3537509ff7cSJens Wiklander 
3547509ff7cSJens Wiklander 		switch (ELF32_R_TYPE(rel->r_info)) {
355f104c8eeSEtienne Carriere 		case R_ARM_NONE:
356f104c8eeSEtienne Carriere 			/*
357f104c8eeSEtienne Carriere 			 * One would expect linker prevents such useless entry
358f104c8eeSEtienne Carriere 			 * in the relocation table. We still handle this type
359f104c8eeSEtienne Carriere 			 * here in case such entries exist.
360f104c8eeSEtienne Carriere 			 */
361f104c8eeSEtienne Carriere 			break;
3627509ff7cSJens Wiklander 		case R_ARM_ABS32:
3637509ff7cSJens Wiklander 			sym_idx = ELF32_R_SYM(rel->r_info);
364447354c6SJens Wiklander 			if (sym_idx >= num_syms)
365e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
366447354c6SJens Wiklander 				    "Symbol index out of range");
3677509ff7cSJens Wiklander 			if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
3687509ff7cSJens Wiklander 				/* Symbol is external */
3697509ff7cSJens Wiklander 				e32_process_dyn_rel(sym_tab, num_syms, str_tab,
3707509ff7cSJens Wiklander 						    str_tab_size, rel, where);
3717509ff7cSJens Wiklander 			} else {
3727509ff7cSJens Wiklander 				*where += elf->load_addr +
3737509ff7cSJens Wiklander 					  sym_tab[sym_idx].st_value;
3747509ff7cSJens Wiklander 			}
3757509ff7cSJens Wiklander 			break;
3767509ff7cSJens Wiklander 		case R_ARM_REL32:
3777509ff7cSJens Wiklander 			sym_idx = ELF32_R_SYM(rel->r_info);
378447354c6SJens Wiklander 			if (sym_idx >= num_syms)
379e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
380447354c6SJens Wiklander 				    "Symbol index out of range");
3817509ff7cSJens Wiklander 			*where += sym_tab[sym_idx].st_value - rel->r_offset;
3827509ff7cSJens Wiklander 			break;
3837509ff7cSJens Wiklander 		case R_ARM_RELATIVE:
3847509ff7cSJens Wiklander 			*where += elf->load_addr;
3857509ff7cSJens Wiklander 			break;
3867509ff7cSJens Wiklander 		case R_ARM_GLOB_DAT:
3877509ff7cSJens Wiklander 		case R_ARM_JUMP_SLOT:
3886897ad0fSJens Wiklander 			if (!sym_tab)
3896897ad0fSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
3906897ad0fSJens Wiklander 				    "Missing symbol table");
3917509ff7cSJens Wiklander 			e32_process_dyn_rel(sym_tab, num_syms, str_tab,
3927509ff7cSJens Wiklander 					    str_tab_size, rel, where);
3937509ff7cSJens Wiklander 			break;
394c88ba125SJerome Forissier 		case R_ARM_TLS_DTPMOD32:
3956897ad0fSJens Wiklander 			if (!sym_tab)
3966897ad0fSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
3976897ad0fSJens Wiklander 				    "Missing symbol table");
398c88ba125SJerome Forissier 			mod = elf;
399c88ba125SJerome Forissier 			e32_tls_get_module(sym_tab, num_syms, str_tab,
400c88ba125SJerome Forissier 					   str_tab_size, rel, &mod);
401c88ba125SJerome Forissier 			*where = mod->tls_mod_id;
402c88ba125SJerome Forissier 			break;
403c88ba125SJerome Forissier 		case R_ARM_TLS_DTPOFF32:
4046897ad0fSJens Wiklander 			if (!sym_tab)
4056897ad0fSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
4066897ad0fSJens Wiklander 				    "Missing symbol table");
407c88ba125SJerome Forissier 			e32_tls_resolve(sym_tab, num_syms, str_tab,
408c88ba125SJerome Forissier 					str_tab_size, rel, &val);
409c88ba125SJerome Forissier 			*where = val;
410c88ba125SJerome Forissier 			break;
4117509ff7cSJens Wiklander 		default:
4127509ff7cSJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %d",
4137509ff7cSJens Wiklander 			     ELF32_R_TYPE(rel->r_info));
4147509ff7cSJens Wiklander 		}
4157509ff7cSJens Wiklander 	}
4167509ff7cSJens Wiklander }
4177509ff7cSJens Wiklander 
4187509ff7cSJens Wiklander #ifdef ARM64
419fe684948SJerome Forissier static void e64_get_sym_name(const Elf64_Sym *sym_tab, size_t num_syms,
4207509ff7cSJens Wiklander 			     const char *str_tab, size_t str_tab_size,
421*c44d734bSJerome Forissier 			     Elf64_Rela *rela, const char **name,
422*c44d734bSJerome Forissier 			     bool *weak_undef)
4237509ff7cSJens Wiklander {
4247509ff7cSJens Wiklander 	size_t sym_idx = 0;
4257509ff7cSJens Wiklander 	size_t name_idx = 0;
4267509ff7cSJens Wiklander 
4277509ff7cSJens Wiklander 	sym_idx = ELF64_R_SYM(rela->r_info);
428447354c6SJens Wiklander 	if (sym_idx >= num_syms)
429e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range");
43055e64090SJens Wiklander 	sym_idx = confine_array_index(sym_idx, num_syms);
4317509ff7cSJens Wiklander 
4327509ff7cSJens Wiklander 	name_idx = sym_tab[sym_idx].st_name;
433447354c6SJens Wiklander 	if (name_idx >= str_tab_size)
434e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Name index out of range");
435fe684948SJerome Forissier 	*name = str_tab + name_idx;
436*c44d734bSJerome Forissier 
437*c44d734bSJerome Forissier 	if (sym_tab[sym_idx].st_shndx == SHN_UNDEF &&
438*c44d734bSJerome Forissier 	    ELF64_ST_BIND(sym_tab[sym_idx].st_info) == STB_WEAK)
439*c44d734bSJerome Forissier 		*weak_undef = true;
440*c44d734bSJerome Forissier 	else
441*c44d734bSJerome Forissier 		*weak_undef = false;
442fe684948SJerome Forissier }
4437509ff7cSJens Wiklander 
444fe684948SJerome Forissier static void e64_process_dyn_rela(const Elf64_Sym *sym_tab, size_t num_syms,
445fe684948SJerome Forissier 				 const char *str_tab, size_t str_tab_size,
446fe684948SJerome Forissier 				 Elf64_Rela *rela, Elf64_Addr *where)
447fe684948SJerome Forissier {
448fe684948SJerome Forissier 	const char *name = NULL;
449fe684948SJerome Forissier 	uintptr_t val = 0;
450*c44d734bSJerome Forissier 	bool weak_undef = false;
451fe684948SJerome Forissier 
452*c44d734bSJerome Forissier 	e64_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rela, &name,
453*c44d734bSJerome Forissier 			 &weak_undef);
454*c44d734bSJerome Forissier 	resolve_sym(name, &val, NULL, !weak_undef);
4557509ff7cSJens Wiklander 	*where = val;
4567509ff7cSJens Wiklander }
4577509ff7cSJens Wiklander 
4587bc927faSJerome Forissier static void e64_process_tls_tprel_rela(const Elf64_Sym *sym_tab,
4597bc927faSJerome Forissier 				       size_t num_syms, const char *str_tab,
4607bc927faSJerome Forissier 				       size_t str_tab_size, Elf64_Rela *rela,
4617bc927faSJerome Forissier 				       Elf64_Addr *where, struct ta_elf *elf)
462fe684948SJerome Forissier {
463fe684948SJerome Forissier 	struct ta_elf *mod = NULL;
464*c44d734bSJerome Forissier 	bool weak_undef = false;
465fe684948SJerome Forissier 	const char *name = NULL;
4667bc927faSJerome Forissier 	size_t sym_idx = 0;
467fe684948SJerome Forissier 	vaddr_t symval = 0;
468fe684948SJerome Forissier 
4697bc927faSJerome Forissier 	sym_idx = ELF64_R_SYM(rela->r_info);
4707bc927faSJerome Forissier 	if (sym_idx) {
4717bc927faSJerome Forissier 		e64_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rela,
472*c44d734bSJerome Forissier 				 &name, &weak_undef);
473*c44d734bSJerome Forissier 		resolve_sym(name, &symval, &mod, !weak_undef);
4747bc927faSJerome Forissier 	} else {
4757bc927faSJerome Forissier 		mod = elf;
4767bc927faSJerome Forissier 	}
477fe684948SJerome Forissier 	*where = symval + mod->tls_tcb_offs + rela->r_addend;
478fe684948SJerome Forissier }
479fe684948SJerome Forissier 
4807bc927faSJerome Forissier struct tlsdesc {
4817bc927faSJerome Forissier 	long (*resolver)(struct tlsdesc *td);
4827bc927faSJerome Forissier 	long value;
4837bc927faSJerome Forissier };
4847bc927faSJerome Forissier 
4857bc927faSJerome Forissier /* Helper function written in assembly due to the calling convention */
4867bc927faSJerome Forissier long tlsdesc_resolve(struct tlsdesc *td);
4877bc927faSJerome Forissier 
4887bc927faSJerome Forissier static void e64_process_tlsdesc_rela(const Elf64_Sym *sym_tab, size_t num_syms,
4897bc927faSJerome Forissier 				     const char *str_tab, size_t str_tab_size,
4907bc927faSJerome Forissier 				     Elf64_Rela *rela, Elf64_Addr *where,
4917bc927faSJerome Forissier 				     struct ta_elf *elf)
4927bc927faSJerome Forissier {
4937bc927faSJerome Forissier 	/*
4947bc927faSJerome Forissier 	 * @where points to a pair of 64-bit words in the GOT or PLT which is
4957bc927faSJerome Forissier 	 * mapped to a struct tlsdesc:
4967bc927faSJerome Forissier 	 *
4977bc927faSJerome Forissier 	 * - resolver() must return the offset of the thread-local variable
4987bc927faSJerome Forissier 	 *   relative to TPIDR_EL0.
4997bc927faSJerome Forissier 	 * - value is implementation-dependent. The TLS_TPREL handling code is
5007bc927faSJerome Forissier 	 *   re-used to get the desired offset so that tlsdesc_resolve() just
5017bc927faSJerome Forissier 	 *   needs to return this value.
5027bc927faSJerome Forissier 	 *
5037bc927faSJerome Forissier 	 * Both the TA and ldelf are AArch64 so it is OK to point to a function
5047bc927faSJerome Forissier 	 * in ldelf.
5057bc927faSJerome Forissier 	 */
5067bc927faSJerome Forissier 	*where = (Elf64_Addr)tlsdesc_resolve;
5077bc927faSJerome Forissier 	e64_process_tls_tprel_rela(sym_tab, num_syms, str_tab, str_tab_size,
5087bc927faSJerome Forissier 				   rela, where + 1, elf);
5097bc927faSJerome Forissier }
5107bc927faSJerome Forissier 
5117509ff7cSJens Wiklander static void e64_relocate(struct ta_elf *elf, unsigned int rel_sidx)
5127509ff7cSJens Wiklander {
5137509ff7cSJens Wiklander 	Elf64_Shdr *shdr = elf->shdr;
5147509ff7cSJens Wiklander 	Elf64_Rela *rela = NULL;
5157509ff7cSJens Wiklander 	Elf64_Rela *rela_end = NULL;
5167509ff7cSJens Wiklander 	size_t sym_tab_idx = 0;
5177509ff7cSJens Wiklander 	Elf64_Sym *sym_tab = NULL;
5187509ff7cSJens Wiklander 	size_t num_syms = 0;
5197509ff7cSJens Wiklander 	size_t sh_end = 0;
5207509ff7cSJens Wiklander 	const char *str_tab = NULL;
5217509ff7cSJens Wiklander 	size_t str_tab_size = 0;
5227509ff7cSJens Wiklander 
5237509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_type == SHT_RELA);
5247509ff7cSJens Wiklander 
5257509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_entsize == sizeof(Elf64_Rela));
5267509ff7cSJens Wiklander 
5277509ff7cSJens Wiklander 	sym_tab_idx = shdr[rel_sidx].sh_link;
5287509ff7cSJens Wiklander 	if (sym_tab_idx) {
5297509ff7cSJens Wiklander 		size_t str_tab_idx = 0;
5307509ff7cSJens Wiklander 
531447354c6SJens Wiklander 		if (sym_tab_idx >= elf->e_shnum)
532dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB index out of range");
53355e64090SJens Wiklander 		sym_tab_idx = confine_array_index(sym_tab_idx, elf->e_shnum);
5347509ff7cSJens Wiklander 
5357509ff7cSJens Wiklander 		assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf64_Sym));
5367509ff7cSJens Wiklander 
5377509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
5387509ff7cSJens Wiklander 		if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr,
5397509ff7cSJens Wiklander 				 shdr[sym_tab_idx].sh_size, &sh_end))
540e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Overflow");
541447354c6SJens Wiklander 		if (sh_end >= (elf->max_addr - elf->load_addr))
542dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB out of range");
5437509ff7cSJens Wiklander 
5447509ff7cSJens Wiklander 		sym_tab = (Elf64_Sym *)(elf->load_addr +
5457509ff7cSJens Wiklander 					shdr[sym_tab_idx].sh_addr);
5467509ff7cSJens Wiklander 
5477509ff7cSJens Wiklander 		num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf64_Sym);
5487509ff7cSJens Wiklander 
5497509ff7cSJens Wiklander 		str_tab_idx = shdr[sym_tab_idx].sh_link;
5507509ff7cSJens Wiklander 		if (str_tab_idx) {
55155e64090SJens Wiklander 			if (str_tab_idx >= elf->e_shnum)
552e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
553dcf64f87SJens Wiklander 				    "STRTAB index out of range");
55455e64090SJens Wiklander 			str_tab_idx = confine_array_index(str_tab_idx,
55555e64090SJens Wiklander 							  elf->e_shnum);
55655e64090SJens Wiklander 
5577509ff7cSJens Wiklander 			/* Check the address is inside ELF memory */
5587509ff7cSJens Wiklander 			if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr,
5597509ff7cSJens Wiklander 					 shdr[str_tab_idx].sh_size, &sh_end))
560e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT, "Overflow");
561447354c6SJens Wiklander 			if (sh_end >= (elf->max_addr - elf->load_addr))
562e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
563dcf64f87SJens Wiklander 				    "STRTAB out of range");
5647509ff7cSJens Wiklander 
5657509ff7cSJens Wiklander 			str_tab = (const char *)(elf->load_addr +
5667509ff7cSJens Wiklander 						 shdr[str_tab_idx].sh_addr);
5677509ff7cSJens Wiklander 			str_tab_size = shdr[str_tab_idx].sh_size;
5687509ff7cSJens Wiklander 		}
5697509ff7cSJens Wiklander 	}
5707509ff7cSJens Wiklander 
5717509ff7cSJens Wiklander 	/* Check the address is inside TA memory */
572447354c6SJens Wiklander 	if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr,
573447354c6SJens Wiklander 			 shdr[rel_sidx].sh_size, &sh_end))
574e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Overflow");
575447354c6SJens Wiklander 	if (sh_end >= (elf->max_addr - elf->load_addr))
576dcf64f87SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, ".rel.*/REL out of range");
5777509ff7cSJens Wiklander 	rela = (Elf64_Rela *)(elf->load_addr + shdr[rel_sidx].sh_addr);
5787509ff7cSJens Wiklander 
5797509ff7cSJens Wiklander 	rela_end = rela + shdr[rel_sidx].sh_size / sizeof(Elf64_Rela);
5807509ff7cSJens Wiklander 	for (; rela < rela_end; rela++) {
5817509ff7cSJens Wiklander 		Elf64_Addr *where = NULL;
5827509ff7cSJens Wiklander 		size_t sym_idx = 0;
5837509ff7cSJens Wiklander 
5847509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
585447354c6SJens Wiklander 		if (rela->r_offset >= (elf->max_addr - elf->load_addr))
586e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT,
587447354c6SJens Wiklander 			    "Relocation offset out of range");
5887509ff7cSJens Wiklander 
5897509ff7cSJens Wiklander 		where = (Elf64_Addr *)(elf->load_addr + rela->r_offset);
5907509ff7cSJens Wiklander 
5917509ff7cSJens Wiklander 		switch (ELF64_R_TYPE(rela->r_info)) {
5927a4dc765SEtienne Carriere 		case R_AARCH64_NONE:
5937a4dc765SEtienne Carriere 			/*
5947a4dc765SEtienne Carriere 			 * One would expect linker prevents such useless entry
5957a4dc765SEtienne Carriere 			 * in the relocation table. We still handle this type
5967a4dc765SEtienne Carriere 			 * here in case such entries exist.
5977a4dc765SEtienne Carriere 			 */
5987a4dc765SEtienne Carriere 			break;
5997509ff7cSJens Wiklander 		case R_AARCH64_ABS64:
6007509ff7cSJens Wiklander 			sym_idx = ELF64_R_SYM(rela->r_info);
601447354c6SJens Wiklander 			if (sym_idx >= num_syms)
602e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
603447354c6SJens Wiklander 				    "Symbol index out of range");
60455e64090SJens Wiklander 			sym_idx = confine_array_index(sym_idx, num_syms);
6057509ff7cSJens Wiklander 			if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
6067509ff7cSJens Wiklander 				/* Symbol is external */
6077509ff7cSJens Wiklander 				e64_process_dyn_rela(sym_tab, num_syms, str_tab,
6087509ff7cSJens Wiklander 						     str_tab_size, rela, where);
6097509ff7cSJens Wiklander 			} else {
6107509ff7cSJens Wiklander 				*where = rela->r_addend + elf->load_addr +
6117509ff7cSJens Wiklander 					 sym_tab[sym_idx].st_value;
6127509ff7cSJens Wiklander 			}
6137509ff7cSJens Wiklander 			break;
6147509ff7cSJens Wiklander 		case R_AARCH64_RELATIVE:
6157509ff7cSJens Wiklander 			*where = rela->r_addend + elf->load_addr;
6167509ff7cSJens Wiklander 			break;
6177509ff7cSJens Wiklander 		case R_AARCH64_GLOB_DAT:
6187509ff7cSJens Wiklander 		case R_AARCH64_JUMP_SLOT:
6197509ff7cSJens Wiklander 			e64_process_dyn_rela(sym_tab, num_syms, str_tab,
6207509ff7cSJens Wiklander 					     str_tab_size, rela, where);
6217509ff7cSJens Wiklander 			break;
622fe684948SJerome Forissier 		case R_AARCH64_TLS_TPREL:
6237bc927faSJerome Forissier 			e64_process_tls_tprel_rela(sym_tab, num_syms, str_tab,
6247bc927faSJerome Forissier 						   str_tab_size, rela, where,
6257bc927faSJerome Forissier 						   elf);
6267bc927faSJerome Forissier 			break;
6277bc927faSJerome Forissier 		case R_AARCH64_TLSDESC:
6287bc927faSJerome Forissier 			e64_process_tlsdesc_rela(sym_tab, num_syms, str_tab,
6297bc927faSJerome Forissier 						 str_tab_size, rela, where,
6307bc927faSJerome Forissier 						 elf);
631fe684948SJerome Forissier 			break;
6327509ff7cSJens Wiklander 		default:
6337509ff7cSJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %zd",
6347509ff7cSJens Wiklander 			     ELF64_R_TYPE(rela->r_info));
6357509ff7cSJens Wiklander 		}
6367509ff7cSJens Wiklander 	}
6377509ff7cSJens Wiklander }
6387509ff7cSJens Wiklander #else /*ARM64*/
6395548a710SJerome Forissier static void __noreturn e64_relocate(struct ta_elf *elf __unused,
6407509ff7cSJens Wiklander 				    unsigned int rel_sidx __unused)
6417509ff7cSJens Wiklander {
6427509ff7cSJens Wiklander 	err(TEE_ERROR_NOT_SUPPORTED, "arm64 not supported");
6437509ff7cSJens Wiklander }
6447509ff7cSJens Wiklander #endif /*ARM64*/
6457509ff7cSJens Wiklander 
6467509ff7cSJens Wiklander void ta_elf_relocate(struct ta_elf *elf)
6477509ff7cSJens Wiklander {
6487509ff7cSJens Wiklander 	size_t n = 0;
6497509ff7cSJens Wiklander 
6507509ff7cSJens Wiklander 	if (elf->is_32bit) {
6517509ff7cSJens Wiklander 		Elf32_Shdr *shdr = elf->shdr;
6527509ff7cSJens Wiklander 
6537509ff7cSJens Wiklander 		for (n = 0; n < elf->e_shnum; n++)
6547509ff7cSJens Wiklander 			if (shdr[n].sh_type == SHT_REL)
6557509ff7cSJens Wiklander 				e32_relocate(elf, n);
6567509ff7cSJens Wiklander 	} else {
6577509ff7cSJens Wiklander 		Elf64_Shdr *shdr = elf->shdr;
6587509ff7cSJens Wiklander 
6597509ff7cSJens Wiklander 		for (n = 0; n < elf->e_shnum; n++)
6607509ff7cSJens Wiklander 			if (shdr[n].sh_type == SHT_RELA)
6617509ff7cSJens Wiklander 				e64_relocate(elf, n);
6627509ff7cSJens Wiklander 
6637509ff7cSJens Wiklander 	}
6647509ff7cSJens Wiklander }
665