xref: /optee_os/ldelf/ta_elf_rel.c (revision 1868eb206733e931b6c6c2d85d55e646bc8a2496)
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 
elf_hash(const char * name)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 
gnu_hash(const char * name)35bdf82531SJerome Forissier static uint32_t gnu_hash(const char *name)
36bdf82531SJerome Forissier {
37bdf82531SJerome Forissier 	const unsigned char *p = (const unsigned char *)name;
38bdf82531SJerome Forissier 	uint32_t h = 5381;
39bdf82531SJerome Forissier 
40bdf82531SJerome Forissier 	while (*p)
41bdf82531SJerome Forissier 		h = (h << 5) + h + *p++;
42bdf82531SJerome Forissier 
43bdf82531SJerome Forissier 	return h;
44bdf82531SJerome Forissier }
45bdf82531SJerome Forissier 
sym_compare(struct ta_elf * elf,unsigned int st_bind,unsigned int st_type,size_t st_shndx,size_t st_name,size_t st_value,const char * name,vaddr_t * val,bool weak_ok)46bdf82531SJerome Forissier static bool sym_compare(struct ta_elf *elf, unsigned int st_bind,
4797c5ac19SJens Wiklander 			unsigned int st_type, size_t st_shndx,
4897c5ac19SJens Wiklander 			size_t st_name, size_t st_value, const char *name,
49cf830b2bSJerome Forissier 			vaddr_t *val, bool weak_ok)
507509ff7cSJens Wiklander {
51cf830b2bSJerome Forissier 	bool bind_ok = false;
52cf830b2bSJerome Forissier 
537509ff7cSJens Wiklander 	if (!st_name)
547509ff7cSJens Wiklander 		return false;
557509ff7cSJens Wiklander 	if (st_name > elf->dynstr_size)
5697c5ac19SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol name out of range");
577509ff7cSJens Wiklander 	if (strcmp(name, elf->dynstr + st_name))
587509ff7cSJens Wiklander 		return false;
59cf830b2bSJerome Forissier 	if (st_bind == STB_GLOBAL || (weak_ok && st_bind == STB_WEAK))
60cf830b2bSJerome Forissier 		bind_ok = true;
61cf830b2bSJerome Forissier 	if (!bind_ok)
62cf830b2bSJerome Forissier 		return false;
63cf830b2bSJerome Forissier 	if (st_bind == STB_WEAK && st_shndx == SHN_UNDEF) {
64cf830b2bSJerome Forissier 		if (val)
65cf830b2bSJerome Forissier 			*val = 0;
66cf830b2bSJerome Forissier 		return true;
67cf830b2bSJerome Forissier 	}
68cf830b2bSJerome Forissier 	if (st_shndx == SHN_UNDEF || st_shndx == SHN_XINDEX)
69cf830b2bSJerome Forissier 		return false;
707509ff7cSJens Wiklander 
7197c5ac19SJens Wiklander 	switch (st_type) {
72bb8cd6f0SJerome Forissier 	case STT_NOTYPE:
7397c5ac19SJens Wiklander 	case STT_OBJECT:
7497c5ac19SJens Wiklander 	case STT_FUNC:
75c88ba125SJerome Forissier 		if (st_value > (elf->max_addr - elf->load_addr))
76c88ba125SJerome Forissier 			err(TEE_ERROR_BAD_FORMAT,
77c88ba125SJerome Forissier 			    "Symbol location out of range");
78c88ba125SJerome Forissier 		if (val)
797509ff7cSJens Wiklander 			*val = st_value + elf->load_addr;
8097c5ac19SJens Wiklander 		break;
81c88ba125SJerome Forissier 	case STT_TLS:
82c88ba125SJerome Forissier 		if (val)
83c88ba125SJerome Forissier 			*val = st_value;
84c88ba125SJerome Forissier 		break;
8597c5ac19SJens Wiklander 	default:
8697c5ac19SJens Wiklander 		err(TEE_ERROR_NOT_SUPPORTED, "Symbol type not supported");
8797c5ac19SJens Wiklander 	}
8897c5ac19SJens Wiklander 
897509ff7cSJens Wiklander 	return true;
907509ff7cSJens Wiklander }
917509ff7cSJens Wiklander 
check_found_sym(struct ta_elf * elf,const char * name,vaddr_t * val,bool weak_ok,size_t n)92bdf82531SJerome Forissier static bool check_found_sym(struct ta_elf *elf, const char *name, vaddr_t *val,
93bdf82531SJerome Forissier 			    bool weak_ok, size_t n)
947509ff7cSJens Wiklander {
95bdf82531SJerome Forissier 	Elf32_Sym *sym32 = NULL;
96bdf82531SJerome Forissier 	Elf64_Sym *sym64 = NULL;
97bdf82531SJerome Forissier 	unsigned int st_bind = 0;
98bdf82531SJerome Forissier 	unsigned int st_type = 0;
99bdf82531SJerome Forissier 	size_t st_shndx = 0;
100bdf82531SJerome Forissier 	size_t st_name = 0;
101bdf82531SJerome Forissier 	size_t st_value = 0;
102bdf82531SJerome Forissier 
103bdf82531SJerome Forissier 	if (n >= elf->num_dynsyms)
104bdf82531SJerome Forissier 		err(TEE_ERROR_BAD_FORMAT, "Index out of range");
105bdf82531SJerome Forissier 
106bdf82531SJerome Forissier 	/*
107bdf82531SJerome Forissier 	 * We're loading values from sym[] which later
108bdf82531SJerome Forissier 	 * will be used to load something.
109bdf82531SJerome Forissier 	 * => Spectre V1 pattern, need to cap the index
110bdf82531SJerome Forissier 	 * against speculation.
111bdf82531SJerome Forissier 	 */
112bdf82531SJerome Forissier 	n = confine_array_index(n, elf->num_dynsyms);
113bdf82531SJerome Forissier 
114bdf82531SJerome Forissier 	if (elf->is_32bit) {
115bdf82531SJerome Forissier 		sym32 = elf->dynsymtab;
116bdf82531SJerome Forissier 		st_bind = ELF32_ST_BIND(sym32[n].st_info);
117bdf82531SJerome Forissier 		st_type = ELF32_ST_TYPE(sym32[n].st_info);
118bdf82531SJerome Forissier 		st_shndx = sym32[n].st_shndx;
119bdf82531SJerome Forissier 		st_name = sym32[n].st_name;
120bdf82531SJerome Forissier 		st_value = sym32[n].st_value;
121bdf82531SJerome Forissier 	} else {
122bdf82531SJerome Forissier 		sym64 = elf->dynsymtab;
123bdf82531SJerome Forissier 		st_bind = ELF64_ST_BIND(sym64[n].st_info);
124bdf82531SJerome Forissier 		st_type = ELF64_ST_TYPE(sym64[n].st_info);
125bdf82531SJerome Forissier 		st_shndx = sym64[n].st_shndx;
126bdf82531SJerome Forissier 		st_name = sym64[n].st_name;
127bdf82531SJerome Forissier 		st_value = sym64[n].st_value;
128bdf82531SJerome Forissier 	}
129bdf82531SJerome Forissier 
130bdf82531SJerome Forissier 	return sym_compare(elf, st_bind, st_type, st_shndx, st_name, st_value,
131bdf82531SJerome Forissier 			   name, val, weak_ok);
132bdf82531SJerome Forissier }
133bdf82531SJerome Forissier 
resolve_sym_helper(const char * name,vaddr_t * val,struct ta_elf * elf,bool weak_ok)134bdf82531SJerome Forissier static TEE_Result resolve_sym_helper(const char *name, vaddr_t *val,
135bdf82531SJerome Forissier 				     struct ta_elf *elf, bool weak_ok)
136bdf82531SJerome Forissier {
137bdf82531SJerome Forissier 	uint32_t n = 0;
138bdf82531SJerome Forissier 	uint32_t hash = 0;
139bdf82531SJerome Forissier 
140bdf82531SJerome Forissier 	if (elf->gnu_hashtab) {
141bdf82531SJerome Forissier 		struct gnu_hashtab *h = elf->gnu_hashtab;
142bdf82531SJerome Forissier 		uint32_t *end = (void *)((uint8_t *)elf->gnu_hashtab +
143bdf82531SJerome Forissier 					 elf->gnu_hashtab_size);
144bdf82531SJerome Forissier 		uint32_t *bucket = NULL;
145bdf82531SJerome Forissier 		uint32_t *chain = NULL;
146bdf82531SJerome Forissier 		uint32_t hashval = 0;
147bdf82531SJerome Forissier 
148bdf82531SJerome Forissier 		hash = gnu_hash(name);
149bdf82531SJerome Forissier 
150bdf82531SJerome Forissier 		if (elf->is_32bit) {
151bdf82531SJerome Forissier 			uint32_t *bloom = (void *)(h + 1);
152bdf82531SJerome Forissier 			uint32_t word = bloom[(hash / 32) % h->bloom_size];
153bdf82531SJerome Forissier 			uint32_t mask = BIT32(hash % 32) |
154bdf82531SJerome Forissier 					BIT32((hash >> h->bloom_shift) % 32);
155bdf82531SJerome Forissier 
156bdf82531SJerome Forissier 			if ((word & mask) != mask)
157bdf82531SJerome Forissier 				return TEE_ERROR_ITEM_NOT_FOUND;
158bdf82531SJerome Forissier 			bucket = bloom + h->bloom_size;
159bdf82531SJerome Forissier 		} else {
160bdf82531SJerome Forissier 			uint64_t *bloom = (void *)(h + 1);
161bdf82531SJerome Forissier 			uint64_t word = bloom[(hash / 64) % h->bloom_size];
162bdf82531SJerome Forissier 			uint64_t mask = BIT64(hash % 64) |
163bdf82531SJerome Forissier 					BIT64((hash >> h->bloom_shift) % 64);
164bdf82531SJerome Forissier 
165bdf82531SJerome Forissier 			if ((word & mask) != mask)
166bdf82531SJerome Forissier 				return TEE_ERROR_ITEM_NOT_FOUND;
167bdf82531SJerome Forissier 			bucket = (uint32_t *)(bloom + h->bloom_size);
168bdf82531SJerome Forissier 		}
169bdf82531SJerome Forissier 		chain = bucket + h->nbuckets;
170bdf82531SJerome Forissier 
171bdf82531SJerome Forissier 		n = bucket[hash % h->nbuckets];
172bdf82531SJerome Forissier 		if (n < h->symoffset)
173bdf82531SJerome Forissier 			return TEE_ERROR_ITEM_NOT_FOUND;
174bdf82531SJerome Forissier 
175bdf82531SJerome Forissier 		hash |= 1;
176bdf82531SJerome Forissier 		do {
177bdf82531SJerome Forissier 			size_t idx = n - h->symoffset;
178bdf82531SJerome Forissier 
179bdf82531SJerome Forissier 			if (chain + idx > end)
180bdf82531SJerome Forissier 				return TEE_ERROR_ITEM_NOT_FOUND;
181bdf82531SJerome Forissier 
182bdf82531SJerome Forissier 			hashval = chain[idx];
183bdf82531SJerome Forissier 
184bdf82531SJerome Forissier 			if ((hashval | 1) == hash &&
185bdf82531SJerome Forissier 			    check_found_sym(elf, name, val, weak_ok, n))
186bdf82531SJerome Forissier 				return TEE_SUCCESS;
187bdf82531SJerome Forissier 
188bdf82531SJerome Forissier 			n++;
189bdf82531SJerome Forissier 		} while (!(hashval & 1));
190bdf82531SJerome Forissier 	} else if (elf->hashtab) {
1919f392760SJerome Forissier 		/*
1929f392760SJerome Forissier 		 * Using uint32_t here for convenience because both Elf64_Word
1939f392760SJerome Forissier 		 * and Elf32_Word are 32-bit types
1949f392760SJerome Forissier 		 */
1959f392760SJerome Forissier 		uint32_t *hashtab = elf->hashtab;
1969f392760SJerome Forissier 		uint32_t nbuckets = hashtab[0];
1979f392760SJerome Forissier 		uint32_t nchains = hashtab[1];
1989f392760SJerome Forissier 		uint32_t *bucket = &hashtab[2];
1999f392760SJerome Forissier 		uint32_t *chain = &bucket[nbuckets];
2009f392760SJerome Forissier 
201*1868eb20SGyorgy Szing 		if (!nbuckets)
202*1868eb20SGyorgy Szing 			return TEE_ERROR_ITEM_NOT_FOUND;
203*1868eb20SGyorgy Szing 
204bdf82531SJerome Forissier 		hash = elf_hash(name);
2057509ff7cSJens Wiklander 
2069f392760SJerome Forissier 		for (n = bucket[hash % nbuckets]; n; n = chain[n]) {
207bdf82531SJerome Forissier 			if (n >= nchains)
208bdf82531SJerome Forissier 				err(TEE_ERROR_BAD_FORMAT, "Index out of range");
209bdf82531SJerome Forissier 			if (check_found_sym(elf, name, val, weak_ok, n))
210c86f218cSJens Wiklander 				return TEE_SUCCESS;
2117509ff7cSJens Wiklander 		}
2127509ff7cSJens Wiklander 	}
213ebef121cSJerome Forissier 
214ebef121cSJerome Forissier 	return TEE_ERROR_ITEM_NOT_FOUND;
2157509ff7cSJens Wiklander }
216c86f218cSJens Wiklander 
217cf830b2bSJerome Forissier /*
218cf830b2bSJerome Forissier  * Look for named symbol in @elf, or all modules if @elf == NULL. Global symbols
219cf830b2bSJerome Forissier  * are searched first, then weak ones. Last option, when at least one weak but
220cf830b2bSJerome Forissier  * undefined symbol exists, resolve to zero. Otherwise return
221cf830b2bSJerome Forissier  * TEE_ERROR_ITEM_NOT_FOUND.
222c88ba125SJerome Forissier  * @val (if != 0) receives the symbol value
223c88ba125SJerome Forissier  * @found_elf (if != 0) receives the module where the symbol is found
224cf830b2bSJerome Forissier  */
ta_elf_resolve_sym(const char * name,vaddr_t * val,struct ta_elf ** found_elf,struct ta_elf * elf)225ebef121cSJerome Forissier TEE_Result ta_elf_resolve_sym(const char *name, vaddr_t *val,
226c88ba125SJerome Forissier 			      struct ta_elf **found_elf,
227ebef121cSJerome Forissier 			      struct ta_elf *elf)
228ebef121cSJerome Forissier {
229cf830b2bSJerome Forissier 	if (elf) {
230cf830b2bSJerome Forissier 		/* Search global symbols */
231bdf82531SJerome Forissier 		if (!resolve_sym_helper(name, val, elf, false /* !weak_ok */))
232c88ba125SJerome Forissier 			goto success;
233cf830b2bSJerome Forissier 		/* Search weak symbols */
234bdf82531SJerome Forissier 		if (!resolve_sym_helper(name, val, elf, true /* weak_ok */))
235c88ba125SJerome Forissier 			goto success;
236cf830b2bSJerome Forissier 	}
237cf830b2bSJerome Forissier 
238cf830b2bSJerome Forissier 	TAILQ_FOREACH(elf, &main_elf_queue, link) {
239bdf82531SJerome Forissier 		if (!resolve_sym_helper(name, val, elf, false /* !weak_ok */))
240c88ba125SJerome Forissier 			goto success;
241bdf82531SJerome Forissier 		if (!resolve_sym_helper(name, val, elf, true /* weak_ok */))
242c88ba125SJerome Forissier 			goto success;
243cf830b2bSJerome Forissier 	}
244ebef121cSJerome Forissier 
245c86f218cSJens Wiklander 	return TEE_ERROR_ITEM_NOT_FOUND;
246c88ba125SJerome Forissier 
247c88ba125SJerome Forissier success:
248c88ba125SJerome Forissier 	if (found_elf)
249c88ba125SJerome Forissier 		*found_elf = elf;
250c88ba125SJerome Forissier 	return TEE_SUCCESS;
251c86f218cSJens Wiklander }
252c86f218cSJens Wiklander 
e32_get_sym_name(const Elf32_Sym * sym_tab,size_t num_syms,const char * str_tab,size_t str_tab_size,Elf32_Rel * rel,const char ** name,bool * weak_undef)253c88ba125SJerome Forissier static void e32_get_sym_name(const Elf32_Sym *sym_tab, size_t num_syms,
2547509ff7cSJens Wiklander 			     const char *str_tab, size_t str_tab_size,
255c44d734bSJerome Forissier 			     Elf32_Rel *rel, const char **name,
256c44d734bSJerome Forissier 			     bool *weak_undef)
2577509ff7cSJens Wiklander {
2587509ff7cSJens Wiklander 	size_t sym_idx = 0;
2597509ff7cSJens Wiklander 	size_t name_idx = 0;
2607509ff7cSJens Wiklander 
2617509ff7cSJens Wiklander 	sym_idx = ELF32_R_SYM(rel->r_info);
262447354c6SJens Wiklander 	if (sym_idx >= num_syms)
263e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range");
26455e64090SJens Wiklander 	sym_idx = confine_array_index(sym_idx, num_syms);
2657509ff7cSJens Wiklander 
2667509ff7cSJens Wiklander 	name_idx = sym_tab[sym_idx].st_name;
267447354c6SJens Wiklander 	if (name_idx >= str_tab_size)
268e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Name index out of range");
269c88ba125SJerome Forissier 	*name = str_tab + name_idx;
270c44d734bSJerome Forissier 
271c44d734bSJerome Forissier 	if (!weak_undef)
272c44d734bSJerome Forissier 		return;
273c44d734bSJerome Forissier 	if (sym_tab[sym_idx].st_shndx == SHN_UNDEF &&
274c44d734bSJerome Forissier 	    ELF32_ST_BIND(sym_tab[sym_idx].st_info) == STB_WEAK)
275c44d734bSJerome Forissier 		*weak_undef = true;
276c44d734bSJerome Forissier 	else
277c44d734bSJerome Forissier 		*weak_undef = false;
278c88ba125SJerome Forissier }
2797509ff7cSJens Wiklander 
resolve_sym(const char * name,vaddr_t * val,struct ta_elf ** mod,bool err_if_not_found)280c44d734bSJerome Forissier static void resolve_sym(const char *name, vaddr_t *val, struct ta_elf **mod,
281c44d734bSJerome Forissier 			bool err_if_not_found)
282c88ba125SJerome Forissier {
283c88ba125SJerome Forissier 	TEE_Result res = ta_elf_resolve_sym(name, val, mod, NULL);
284c88ba125SJerome Forissier 
285c44d734bSJerome Forissier 	if (res) {
286c44d734bSJerome Forissier 		if (err_if_not_found)
287c88ba125SJerome Forissier 			err(res, "Symbol %s not found", name);
2884584d00cSClement Faure 		else if (val)
289c44d734bSJerome Forissier 			*val = 0;
290c44d734bSJerome Forissier 	}
291c88ba125SJerome Forissier }
292c88ba125SJerome Forissier 
e32_process_dyn_rel(const Elf32_Sym * sym_tab,size_t num_syms,const char * str_tab,size_t str_tab_size,Elf32_Rel * rel,Elf32_Addr * where)293c88ba125SJerome Forissier static void e32_process_dyn_rel(const Elf32_Sym *sym_tab, size_t num_syms,
294c88ba125SJerome Forissier 				const char *str_tab, size_t str_tab_size,
295c88ba125SJerome Forissier 				Elf32_Rel *rel, Elf32_Addr *where)
296c88ba125SJerome Forissier {
297c88ba125SJerome Forissier 	const char *name = NULL;
298c88ba125SJerome Forissier 	vaddr_t val = 0;
299c44d734bSJerome Forissier 	bool weak_undef = false;
300c88ba125SJerome Forissier 
301c44d734bSJerome Forissier 	e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name,
302c44d734bSJerome Forissier 			 &weak_undef);
303c44d734bSJerome Forissier 	resolve_sym(name, &val, NULL, !weak_undef);
3047509ff7cSJens Wiklander 	*where = val;
3057509ff7cSJens Wiklander }
3067509ff7cSJens Wiklander 
e32_tls_get_module(const Elf32_Sym * sym_tab,size_t num_syms,const char * str_tab,size_t str_tab_size,Elf32_Rel * rel,struct ta_elf ** mod)307c88ba125SJerome Forissier static void e32_tls_get_module(const Elf32_Sym *sym_tab, size_t num_syms,
308c88ba125SJerome Forissier 			       const char *str_tab, size_t str_tab_size,
309c88ba125SJerome Forissier 			       Elf32_Rel *rel, struct ta_elf **mod)
310c88ba125SJerome Forissier {
311c88ba125SJerome Forissier 	const char *name = NULL;
312c88ba125SJerome Forissier 	size_t sym_idx = 0;
313c88ba125SJerome Forissier 
314c88ba125SJerome Forissier 	sym_idx = ELF32_R_SYM(rel->r_info);
315c88ba125SJerome Forissier 	if (sym_idx >= num_syms)
316c88ba125SJerome Forissier 		err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range");
317c88ba125SJerome Forissier 	sym_idx = confine_array_index(sym_idx, num_syms);
318c88ba125SJerome Forissier 	if (!sym_idx || sym_tab[sym_idx].st_shndx != SHN_UNDEF) {
319c88ba125SJerome Forissier 		/* No symbol, or symbol is defined in current module */
320c88ba125SJerome Forissier 		return;
321c88ba125SJerome Forissier 	}
322c88ba125SJerome Forissier 
323c44d734bSJerome Forissier 	e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name,
324c44d734bSJerome Forissier 			 NULL);
325c44d734bSJerome Forissier 	resolve_sym(name, NULL, mod, false);
326c88ba125SJerome Forissier }
327c88ba125SJerome Forissier 
e32_tls_resolve(const Elf32_Sym * sym_tab,size_t num_syms,const char * str_tab,size_t str_tab_size,Elf32_Rel * rel,vaddr_t * val)328c88ba125SJerome Forissier static void e32_tls_resolve(const Elf32_Sym *sym_tab, size_t num_syms,
329c88ba125SJerome Forissier 			    const char *str_tab, size_t str_tab_size,
330c88ba125SJerome Forissier 			    Elf32_Rel *rel, vaddr_t *val)
331c88ba125SJerome Forissier {
332c88ba125SJerome Forissier 	const char *name = NULL;
333c88ba125SJerome Forissier 
334c44d734bSJerome Forissier 	e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name,
335c44d734bSJerome Forissier 			 NULL);
336c44d734bSJerome Forissier 	resolve_sym(name, val, NULL, false);
337c88ba125SJerome Forissier }
338c88ba125SJerome Forissier 
e32_relocate(struct ta_elf * elf,unsigned int rel_sidx)3397509ff7cSJens Wiklander static void e32_relocate(struct ta_elf *elf, unsigned int rel_sidx)
3407509ff7cSJens Wiklander {
3417509ff7cSJens Wiklander 	Elf32_Shdr *shdr = elf->shdr;
3427509ff7cSJens Wiklander 	Elf32_Rel *rel = NULL;
3437509ff7cSJens Wiklander 	Elf32_Rel *rel_end = NULL;
3447509ff7cSJens Wiklander 	size_t sym_tab_idx = 0;
3457509ff7cSJens Wiklander 	Elf32_Sym *sym_tab = NULL;
3467509ff7cSJens Wiklander 	size_t num_syms = 0;
3477509ff7cSJens Wiklander 	size_t sh_end = 0;
3487509ff7cSJens Wiklander 	const char *str_tab = NULL;
3497509ff7cSJens Wiklander 	size_t str_tab_size = 0;
3507509ff7cSJens Wiklander 
3517509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_type == SHT_REL);
3527509ff7cSJens Wiklander 
3537509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_entsize == sizeof(Elf32_Rel));
3547509ff7cSJens Wiklander 
3557509ff7cSJens Wiklander 	sym_tab_idx = shdr[rel_sidx].sh_link;
3567509ff7cSJens Wiklander 	if (sym_tab_idx) {
3577509ff7cSJens Wiklander 		size_t str_tab_idx = 0;
3587509ff7cSJens Wiklander 
359447354c6SJens Wiklander 		if (sym_tab_idx >= elf->e_shnum)
360dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB index out of range");
36155e64090SJens Wiklander 		sym_tab_idx = confine_array_index(sym_tab_idx, elf->e_shnum);
3627509ff7cSJens Wiklander 
3637509ff7cSJens Wiklander 		assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf32_Sym));
3647509ff7cSJens Wiklander 
3657509ff7cSJens Wiklander 		/* Check the address is inside ELF memory */
3667509ff7cSJens Wiklander 		if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr,
3677509ff7cSJens Wiklander 				 shdr[sym_tab_idx].sh_size, &sh_end))
368e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Overflow");
369447354c6SJens Wiklander 		if (sh_end >= (elf->max_addr - elf->load_addr))
370dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB out of range");
3717509ff7cSJens Wiklander 
3727509ff7cSJens Wiklander 		sym_tab = (Elf32_Sym *)(elf->load_addr +
3737509ff7cSJens Wiklander 					shdr[sym_tab_idx].sh_addr);
3747509ff7cSJens Wiklander 
3757509ff7cSJens Wiklander 		num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf32_Sym);
3767509ff7cSJens Wiklander 
3777509ff7cSJens Wiklander 		str_tab_idx = shdr[sym_tab_idx].sh_link;
3787509ff7cSJens Wiklander 		if (str_tab_idx) {
37955e64090SJens Wiklander 			if (str_tab_idx >= elf->e_shnum)
380e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
381dcf64f87SJens Wiklander 				    "STRTAB index out of range");
38255e64090SJens Wiklander 			str_tab_idx = confine_array_index(str_tab_idx,
38355e64090SJens Wiklander 							  elf->e_shnum);
38455e64090SJens Wiklander 
3857509ff7cSJens Wiklander 			/* Check the address is inside ELF memory */
3867509ff7cSJens Wiklander 			if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr,
3877509ff7cSJens Wiklander 					 shdr[str_tab_idx].sh_size, &sh_end))
388e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT, "Overflow");
389447354c6SJens Wiklander 			if (sh_end >= (elf->max_addr - elf->load_addr))
390e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
391dcf64f87SJens Wiklander 				    "STRTAB out of range");
3927509ff7cSJens Wiklander 
3937509ff7cSJens Wiklander 			str_tab = (const char *)(elf->load_addr +
3947509ff7cSJens Wiklander 						 shdr[str_tab_idx].sh_addr);
3957509ff7cSJens Wiklander 			str_tab_size = shdr[str_tab_idx].sh_size;
3967509ff7cSJens Wiklander 		}
3977509ff7cSJens Wiklander 	}
3987509ff7cSJens Wiklander 
3997509ff7cSJens Wiklander 	/* Check the address is inside TA memory */
400447354c6SJens Wiklander 	if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr,
401447354c6SJens Wiklander 			 shdr[rel_sidx].sh_size, &sh_end))
402e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Overflow");
403447354c6SJens Wiklander 	if (sh_end >= (elf->max_addr - elf->load_addr))
404dcf64f87SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, ".rel.*/REL out of range");
4057509ff7cSJens Wiklander 	rel = (Elf32_Rel *)(elf->load_addr + shdr[rel_sidx].sh_addr);
4067509ff7cSJens Wiklander 
4077509ff7cSJens Wiklander 	rel_end = rel + shdr[rel_sidx].sh_size / sizeof(Elf32_Rel);
4087509ff7cSJens Wiklander 	for (; rel < rel_end; rel++) {
409c88ba125SJerome Forissier 		struct ta_elf *mod = NULL;
4107509ff7cSJens Wiklander 		Elf32_Addr *where = NULL;
4117509ff7cSJens Wiklander 		size_t sym_idx = 0;
412c88ba125SJerome Forissier 		vaddr_t val = 0;
4137509ff7cSJens Wiklander 
4147509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
415447354c6SJens Wiklander 		if (rel->r_offset >= (elf->max_addr - elf->load_addr))
416e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT,
417447354c6SJens Wiklander 			    "Relocation offset out of range");
4187509ff7cSJens Wiklander 		where = (Elf32_Addr *)(elf->load_addr + rel->r_offset);
4197509ff7cSJens Wiklander 
4207509ff7cSJens Wiklander 		switch (ELF32_R_TYPE(rel->r_info)) {
421f104c8eeSEtienne Carriere 		case R_ARM_NONE:
422f104c8eeSEtienne Carriere 			/*
423f104c8eeSEtienne Carriere 			 * One would expect linker prevents such useless entry
424f104c8eeSEtienne Carriere 			 * in the relocation table. We still handle this type
425f104c8eeSEtienne Carriere 			 * here in case such entries exist.
426f104c8eeSEtienne Carriere 			 */
427f104c8eeSEtienne Carriere 			break;
4287509ff7cSJens Wiklander 		case R_ARM_ABS32:
4297509ff7cSJens Wiklander 			sym_idx = ELF32_R_SYM(rel->r_info);
430447354c6SJens Wiklander 			if (sym_idx >= num_syms)
431e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
432447354c6SJens Wiklander 				    "Symbol index out of range");
4337509ff7cSJens Wiklander 			if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
4347509ff7cSJens Wiklander 				/* Symbol is external */
4357509ff7cSJens Wiklander 				e32_process_dyn_rel(sym_tab, num_syms, str_tab,
4367509ff7cSJens Wiklander 						    str_tab_size, rel, where);
4377509ff7cSJens Wiklander 			} else {
4387509ff7cSJens Wiklander 				*where += elf->load_addr +
4397509ff7cSJens Wiklander 					  sym_tab[sym_idx].st_value;
4407509ff7cSJens Wiklander 			}
4417509ff7cSJens Wiklander 			break;
4427509ff7cSJens Wiklander 		case R_ARM_REL32:
4437509ff7cSJens Wiklander 			sym_idx = ELF32_R_SYM(rel->r_info);
444447354c6SJens Wiklander 			if (sym_idx >= num_syms)
445e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
446447354c6SJens Wiklander 				    "Symbol index out of range");
4477509ff7cSJens Wiklander 			*where += sym_tab[sym_idx].st_value - rel->r_offset;
4487509ff7cSJens Wiklander 			break;
4497509ff7cSJens Wiklander 		case R_ARM_RELATIVE:
4507509ff7cSJens Wiklander 			*where += elf->load_addr;
4517509ff7cSJens Wiklander 			break;
4527509ff7cSJens Wiklander 		case R_ARM_GLOB_DAT:
4537509ff7cSJens Wiklander 		case R_ARM_JUMP_SLOT:
4546897ad0fSJens Wiklander 			if (!sym_tab)
4556897ad0fSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
4566897ad0fSJens Wiklander 				    "Missing symbol table");
4577509ff7cSJens Wiklander 			e32_process_dyn_rel(sym_tab, num_syms, str_tab,
4587509ff7cSJens Wiklander 					    str_tab_size, rel, where);
4597509ff7cSJens Wiklander 			break;
460c88ba125SJerome Forissier 		case R_ARM_TLS_DTPMOD32:
4616897ad0fSJens Wiklander 			if (!sym_tab)
4626897ad0fSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
4636897ad0fSJens Wiklander 				    "Missing symbol table");
464c88ba125SJerome Forissier 			mod = elf;
465c88ba125SJerome Forissier 			e32_tls_get_module(sym_tab, num_syms, str_tab,
466c88ba125SJerome Forissier 					   str_tab_size, rel, &mod);
467c88ba125SJerome Forissier 			*where = mod->tls_mod_id;
468c88ba125SJerome Forissier 			break;
469c88ba125SJerome Forissier 		case R_ARM_TLS_DTPOFF32:
4706897ad0fSJens Wiklander 			if (!sym_tab)
4716897ad0fSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
4726897ad0fSJens Wiklander 				    "Missing symbol table");
473c88ba125SJerome Forissier 			e32_tls_resolve(sym_tab, num_syms, str_tab,
474c88ba125SJerome Forissier 					str_tab_size, rel, &val);
475c88ba125SJerome Forissier 			*where = val;
476c88ba125SJerome Forissier 			break;
4777509ff7cSJens Wiklander 		default:
4787509ff7cSJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %d",
4797509ff7cSJens Wiklander 			     ELF32_R_TYPE(rel->r_info));
4807509ff7cSJens Wiklander 		}
4817509ff7cSJens Wiklander 	}
4827509ff7cSJens Wiklander }
4837509ff7cSJens Wiklander 
4848fab4371Sliushiwei #if defined(ARM64) || defined(RV64)
e64_get_sym_name(const Elf64_Sym * sym_tab,size_t num_syms,const char * str_tab,size_t str_tab_size,Elf64_Rela * rela,const char ** name,bool * weak_undef)485fe684948SJerome Forissier static void e64_get_sym_name(const Elf64_Sym *sym_tab, size_t num_syms,
4867509ff7cSJens Wiklander 			     const char *str_tab, size_t str_tab_size,
487c44d734bSJerome Forissier 			     Elf64_Rela *rela, const char **name,
488c44d734bSJerome Forissier 			     bool *weak_undef)
4897509ff7cSJens Wiklander {
4907509ff7cSJens Wiklander 	size_t sym_idx = 0;
4917509ff7cSJens Wiklander 	size_t name_idx = 0;
4927509ff7cSJens Wiklander 
4937509ff7cSJens Wiklander 	sym_idx = ELF64_R_SYM(rela->r_info);
494447354c6SJens Wiklander 	if (sym_idx >= num_syms)
495e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range");
49655e64090SJens Wiklander 	sym_idx = confine_array_index(sym_idx, num_syms);
4977509ff7cSJens Wiklander 
4987509ff7cSJens Wiklander 	name_idx = sym_tab[sym_idx].st_name;
499447354c6SJens Wiklander 	if (name_idx >= str_tab_size)
500e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Name index out of range");
501fe684948SJerome Forissier 	*name = str_tab + name_idx;
502c44d734bSJerome Forissier 
503c44d734bSJerome Forissier 	if (sym_tab[sym_idx].st_shndx == SHN_UNDEF &&
504c44d734bSJerome Forissier 	    ELF64_ST_BIND(sym_tab[sym_idx].st_info) == STB_WEAK)
505c44d734bSJerome Forissier 		*weak_undef = true;
506c44d734bSJerome Forissier 	else
507c44d734bSJerome Forissier 		*weak_undef = false;
508fe684948SJerome Forissier }
5097509ff7cSJens Wiklander 
e64_process_dyn_rela(const Elf64_Sym * sym_tab,size_t num_syms,const char * str_tab,size_t str_tab_size,Elf64_Rela * rela,Elf64_Addr * where)510fe684948SJerome Forissier static void e64_process_dyn_rela(const Elf64_Sym *sym_tab, size_t num_syms,
511fe684948SJerome Forissier 				 const char *str_tab, size_t str_tab_size,
512fe684948SJerome Forissier 				 Elf64_Rela *rela, Elf64_Addr *where)
513fe684948SJerome Forissier {
514fe684948SJerome Forissier 	const char *name = NULL;
515fe684948SJerome Forissier 	uintptr_t val = 0;
516c44d734bSJerome Forissier 	bool weak_undef = false;
517fe684948SJerome Forissier 
518c44d734bSJerome Forissier 	e64_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rela, &name,
519c44d734bSJerome Forissier 			 &weak_undef);
520c44d734bSJerome Forissier 	resolve_sym(name, &val, NULL, !weak_undef);
5217509ff7cSJens Wiklander 	*where = val;
5227509ff7cSJens Wiklander }
5237509ff7cSJens Wiklander 
5248fab4371Sliushiwei #ifdef ARM64
e64_process_tls_tprel_rela(const Elf64_Sym * sym_tab,size_t num_syms,const char * str_tab,size_t str_tab_size,Elf64_Rela * rela,Elf64_Addr * where,struct ta_elf * elf)5257bc927faSJerome Forissier static void e64_process_tls_tprel_rela(const Elf64_Sym *sym_tab,
5267bc927faSJerome Forissier 				       size_t num_syms, const char *str_tab,
5277bc927faSJerome Forissier 				       size_t str_tab_size, Elf64_Rela *rela,
5287bc927faSJerome Forissier 				       Elf64_Addr *where, struct ta_elf *elf)
529fe684948SJerome Forissier {
530fe684948SJerome Forissier 	struct ta_elf *mod = NULL;
531c44d734bSJerome Forissier 	bool weak_undef = false;
532fe684948SJerome Forissier 	const char *name = NULL;
5337bc927faSJerome Forissier 	size_t sym_idx = 0;
534fe684948SJerome Forissier 	vaddr_t symval = 0;
535fe684948SJerome Forissier 
5367bc927faSJerome Forissier 	sym_idx = ELF64_R_SYM(rela->r_info);
5377bc927faSJerome Forissier 	if (sym_idx) {
5387bc927faSJerome Forissier 		e64_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rela,
539c44d734bSJerome Forissier 				 &name, &weak_undef);
540c44d734bSJerome Forissier 		resolve_sym(name, &symval, &mod, !weak_undef);
5417bc927faSJerome Forissier 	} else {
5427bc927faSJerome Forissier 		mod = elf;
5437bc927faSJerome Forissier 	}
544fe684948SJerome Forissier 	*where = symval + mod->tls_tcb_offs + rela->r_addend;
545fe684948SJerome Forissier }
546fe684948SJerome Forissier 
5477bc927faSJerome Forissier struct tlsdesc {
5487bc927faSJerome Forissier 	long (*resolver)(struct tlsdesc *td);
5497bc927faSJerome Forissier 	long value;
5507bc927faSJerome Forissier };
5517bc927faSJerome Forissier 
5527bc927faSJerome Forissier /* Helper function written in assembly due to the calling convention */
5537bc927faSJerome Forissier long tlsdesc_resolve(struct tlsdesc *td);
5547bc927faSJerome Forissier 
e64_process_tlsdesc_rela(const Elf64_Sym * sym_tab,size_t num_syms,const char * str_tab,size_t str_tab_size,Elf64_Rela * rela,Elf64_Addr * where,struct ta_elf * elf)5557bc927faSJerome Forissier static void e64_process_tlsdesc_rela(const Elf64_Sym *sym_tab, size_t num_syms,
5567bc927faSJerome Forissier 				     const char *str_tab, size_t str_tab_size,
5577bc927faSJerome Forissier 				     Elf64_Rela *rela, Elf64_Addr *where,
5587bc927faSJerome Forissier 				     struct ta_elf *elf)
5597bc927faSJerome Forissier {
5607bc927faSJerome Forissier 	/*
5617bc927faSJerome Forissier 	 * @where points to a pair of 64-bit words in the GOT or PLT which is
5627bc927faSJerome Forissier 	 * mapped to a struct tlsdesc:
5637bc927faSJerome Forissier 	 *
5647bc927faSJerome Forissier 	 * - resolver() must return the offset of the thread-local variable
5657bc927faSJerome Forissier 	 *   relative to TPIDR_EL0.
5667bc927faSJerome Forissier 	 * - value is implementation-dependent. The TLS_TPREL handling code is
5677bc927faSJerome Forissier 	 *   re-used to get the desired offset so that tlsdesc_resolve() just
5687bc927faSJerome Forissier 	 *   needs to return this value.
5697bc927faSJerome Forissier 	 *
5707bc927faSJerome Forissier 	 * Both the TA and ldelf are AArch64 so it is OK to point to a function
5717bc927faSJerome Forissier 	 * in ldelf.
5727bc927faSJerome Forissier 	 */
5737bc927faSJerome Forissier 	*where = (Elf64_Addr)tlsdesc_resolve;
5747bc927faSJerome Forissier 	e64_process_tls_tprel_rela(sym_tab, num_syms, str_tab, str_tab_size,
5757bc927faSJerome Forissier 				   rela, where + 1, elf);
5767bc927faSJerome Forissier }
5778fab4371Sliushiwei #endif /*ARM64*/
5787bc927faSJerome Forissier 
e64_relocate(struct ta_elf * elf,unsigned int rel_sidx)5797509ff7cSJens Wiklander static void e64_relocate(struct ta_elf *elf, unsigned int rel_sidx)
5807509ff7cSJens Wiklander {
5817509ff7cSJens Wiklander 	Elf64_Shdr *shdr = elf->shdr;
5827509ff7cSJens Wiklander 	Elf64_Rela *rela = NULL;
5837509ff7cSJens Wiklander 	Elf64_Rela *rela_end = NULL;
5847509ff7cSJens Wiklander 	size_t sym_tab_idx = 0;
5857509ff7cSJens Wiklander 	Elf64_Sym *sym_tab = NULL;
5867509ff7cSJens Wiklander 	size_t num_syms = 0;
5877509ff7cSJens Wiklander 	size_t sh_end = 0;
5887509ff7cSJens Wiklander 	const char *str_tab = NULL;
5897509ff7cSJens Wiklander 	size_t str_tab_size = 0;
5907509ff7cSJens Wiklander 
5917509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_type == SHT_RELA);
5927509ff7cSJens Wiklander 
5937509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_entsize == sizeof(Elf64_Rela));
5947509ff7cSJens Wiklander 
5957509ff7cSJens Wiklander 	sym_tab_idx = shdr[rel_sidx].sh_link;
5967509ff7cSJens Wiklander 	if (sym_tab_idx) {
5977509ff7cSJens Wiklander 		size_t str_tab_idx = 0;
5987509ff7cSJens Wiklander 
599447354c6SJens Wiklander 		if (sym_tab_idx >= elf->e_shnum)
600dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB index out of range");
60155e64090SJens Wiklander 		sym_tab_idx = confine_array_index(sym_tab_idx, elf->e_shnum);
6027509ff7cSJens Wiklander 
6037509ff7cSJens Wiklander 		assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf64_Sym));
6047509ff7cSJens Wiklander 
6057509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
6067509ff7cSJens Wiklander 		if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr,
6077509ff7cSJens Wiklander 				 shdr[sym_tab_idx].sh_size, &sh_end))
608e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Overflow");
609447354c6SJens Wiklander 		if (sh_end >= (elf->max_addr - elf->load_addr))
610dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB out of range");
6117509ff7cSJens Wiklander 
6127509ff7cSJens Wiklander 		sym_tab = (Elf64_Sym *)(elf->load_addr +
6137509ff7cSJens Wiklander 					shdr[sym_tab_idx].sh_addr);
6147509ff7cSJens Wiklander 
6157509ff7cSJens Wiklander 		num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf64_Sym);
6167509ff7cSJens Wiklander 
6177509ff7cSJens Wiklander 		str_tab_idx = shdr[sym_tab_idx].sh_link;
6187509ff7cSJens Wiklander 		if (str_tab_idx) {
61955e64090SJens Wiklander 			if (str_tab_idx >= elf->e_shnum)
620e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
621dcf64f87SJens Wiklander 				    "STRTAB index out of range");
62255e64090SJens Wiklander 			str_tab_idx = confine_array_index(str_tab_idx,
62355e64090SJens Wiklander 							  elf->e_shnum);
62455e64090SJens Wiklander 
6257509ff7cSJens Wiklander 			/* Check the address is inside ELF memory */
6267509ff7cSJens Wiklander 			if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr,
6277509ff7cSJens Wiklander 					 shdr[str_tab_idx].sh_size, &sh_end))
628e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT, "Overflow");
629447354c6SJens Wiklander 			if (sh_end >= (elf->max_addr - elf->load_addr))
630e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
631dcf64f87SJens Wiklander 				    "STRTAB out of range");
6327509ff7cSJens Wiklander 
6337509ff7cSJens Wiklander 			str_tab = (const char *)(elf->load_addr +
6347509ff7cSJens Wiklander 						 shdr[str_tab_idx].sh_addr);
6357509ff7cSJens Wiklander 			str_tab_size = shdr[str_tab_idx].sh_size;
6367509ff7cSJens Wiklander 		}
6377509ff7cSJens Wiklander 	}
6387509ff7cSJens Wiklander 
6397509ff7cSJens Wiklander 	/* Check the address is inside TA memory */
640447354c6SJens Wiklander 	if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr,
641447354c6SJens Wiklander 			 shdr[rel_sidx].sh_size, &sh_end))
642e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Overflow");
643447354c6SJens Wiklander 	if (sh_end >= (elf->max_addr - elf->load_addr))
644dcf64f87SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, ".rel.*/REL out of range");
6457509ff7cSJens Wiklander 	rela = (Elf64_Rela *)(elf->load_addr + shdr[rel_sidx].sh_addr);
6467509ff7cSJens Wiklander 
6477509ff7cSJens Wiklander 	rela_end = rela + shdr[rel_sidx].sh_size / sizeof(Elf64_Rela);
6487509ff7cSJens Wiklander 	for (; rela < rela_end; rela++) {
6497509ff7cSJens Wiklander 		Elf64_Addr *where = NULL;
650209c34dcSJerome Forissier 		size_t sym_idx __maybe_unused = 0;
6517509ff7cSJens Wiklander 
6527509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
653447354c6SJens Wiklander 		if (rela->r_offset >= (elf->max_addr - elf->load_addr))
654e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT,
655447354c6SJens Wiklander 			    "Relocation offset out of range");
6567509ff7cSJens Wiklander 
6577509ff7cSJens Wiklander 		where = (Elf64_Addr *)(elf->load_addr + rela->r_offset);
6587509ff7cSJens Wiklander 
6597509ff7cSJens Wiklander 		switch (ELF64_R_TYPE(rela->r_info)) {
6608fab4371Sliushiwei #ifdef ARM64
6617a4dc765SEtienne Carriere 		case R_AARCH64_NONE:
6627a4dc765SEtienne Carriere 			/*
6637a4dc765SEtienne Carriere 			 * One would expect linker prevents such useless entry
6647a4dc765SEtienne Carriere 			 * in the relocation table. We still handle this type
6657a4dc765SEtienne Carriere 			 * here in case such entries exist.
6667a4dc765SEtienne Carriere 			 */
6677a4dc765SEtienne Carriere 			break;
6687509ff7cSJens Wiklander 		case R_AARCH64_ABS64:
6697509ff7cSJens Wiklander 			sym_idx = ELF64_R_SYM(rela->r_info);
670447354c6SJens Wiklander 			if (sym_idx >= num_syms)
671e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
672447354c6SJens Wiklander 				    "Symbol index out of range");
67355e64090SJens Wiklander 			sym_idx = confine_array_index(sym_idx, num_syms);
6747509ff7cSJens Wiklander 			if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
6757509ff7cSJens Wiklander 				/* Symbol is external */
6767509ff7cSJens Wiklander 				e64_process_dyn_rela(sym_tab, num_syms, str_tab,
6777509ff7cSJens Wiklander 						     str_tab_size, rela, where);
6787509ff7cSJens Wiklander 			} else {
6797509ff7cSJens Wiklander 				*where = rela->r_addend + elf->load_addr +
6807509ff7cSJens Wiklander 					 sym_tab[sym_idx].st_value;
6817509ff7cSJens Wiklander 			}
6827509ff7cSJens Wiklander 			break;
6837509ff7cSJens Wiklander 		case R_AARCH64_RELATIVE:
6847509ff7cSJens Wiklander 			*where = rela->r_addend + elf->load_addr;
6857509ff7cSJens Wiklander 			break;
6867509ff7cSJens Wiklander 		case R_AARCH64_GLOB_DAT:
6877509ff7cSJens Wiklander 		case R_AARCH64_JUMP_SLOT:
6887509ff7cSJens Wiklander 			e64_process_dyn_rela(sym_tab, num_syms, str_tab,
6897509ff7cSJens Wiklander 					     str_tab_size, rela, where);
6907509ff7cSJens Wiklander 			break;
691fe684948SJerome Forissier 		case R_AARCH64_TLS_TPREL:
6927bc927faSJerome Forissier 			e64_process_tls_tprel_rela(sym_tab, num_syms, str_tab,
6937bc927faSJerome Forissier 						   str_tab_size, rela, where,
6947bc927faSJerome Forissier 						   elf);
6957bc927faSJerome Forissier 			break;
6967bc927faSJerome Forissier 		case R_AARCH64_TLSDESC:
6977bc927faSJerome Forissier 			e64_process_tlsdesc_rela(sym_tab, num_syms, str_tab,
6987bc927faSJerome Forissier 						 str_tab_size, rela, where,
6997bc927faSJerome Forissier 						 elf);
700fe684948SJerome Forissier 			break;
7018fab4371Sliushiwei #endif /*ARM64*/
7028fab4371Sliushiwei #ifdef RV64
7038fab4371Sliushiwei 		case R_RISCV_NONE:
7048fab4371Sliushiwei 			/*
7058fab4371Sliushiwei 			 * One would expect linker prevents such useless entry
7068fab4371Sliushiwei 			 * in the relocation table. We still handle this type
7078fab4371Sliushiwei 			 * here in case such entries exist.
7088fab4371Sliushiwei 			 */
7098fab4371Sliushiwei 			break;
7108fab4371Sliushiwei 		case R_RISCV_RELATIVE:
7118fab4371Sliushiwei 			*where = rela->r_addend + elf->load_addr;
7128fab4371Sliushiwei 			break;
7138fab4371Sliushiwei 		case R_RISCV_64:
7148fab4371Sliushiwei 			e64_process_dyn_rela(sym_tab, num_syms, str_tab,
7158fab4371Sliushiwei 					     str_tab_size, rela, where);
7168fab4371Sliushiwei 			*where += rela->r_addend;
7178fab4371Sliushiwei 			break;
7188fab4371Sliushiwei 		case R_RISCV_JUMP_SLOT:
7198fab4371Sliushiwei 			e64_process_dyn_rela(sym_tab, num_syms, str_tab,
7208fab4371Sliushiwei 					     str_tab_size, rela, where);
7218fab4371Sliushiwei 			break;
7228fab4371Sliushiwei #endif /*RV64*/
7237509ff7cSJens Wiklander 		default:
7247509ff7cSJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %zd",
7257509ff7cSJens Wiklander 			     ELF64_R_TYPE(rela->r_info));
7267509ff7cSJens Wiklander 		}
7277509ff7cSJens Wiklander 	}
7287509ff7cSJens Wiklander }
7298fab4371Sliushiwei #else /*ARM64 || RV64*/
e64_relocate(struct ta_elf * elf __unused,unsigned int rel_sidx __unused)7305548a710SJerome Forissier static void __noreturn e64_relocate(struct ta_elf *elf __unused,
7317509ff7cSJens Wiklander 				    unsigned int rel_sidx __unused)
7327509ff7cSJens Wiklander {
7337509ff7cSJens Wiklander 	err(TEE_ERROR_NOT_SUPPORTED, "arm64 not supported");
7347509ff7cSJens Wiklander }
7358fab4371Sliushiwei #endif /*ARM64 || RV64*/
7367509ff7cSJens Wiklander 
ta_elf_relocate(struct ta_elf * elf)7377509ff7cSJens Wiklander void ta_elf_relocate(struct ta_elf *elf)
7387509ff7cSJens Wiklander {
7397509ff7cSJens Wiklander 	size_t n = 0;
7407509ff7cSJens Wiklander 
7417509ff7cSJens Wiklander 	if (elf->is_32bit) {
7427509ff7cSJens Wiklander 		Elf32_Shdr *shdr = elf->shdr;
7437509ff7cSJens Wiklander 
7447509ff7cSJens Wiklander 		for (n = 0; n < elf->e_shnum; n++)
7457509ff7cSJens Wiklander 			if (shdr[n].sh_type == SHT_REL)
7467509ff7cSJens Wiklander 				e32_relocate(elf, n);
7477509ff7cSJens Wiklander 	} else {
7487509ff7cSJens Wiklander 		Elf64_Shdr *shdr = elf->shdr;
7497509ff7cSJens Wiklander 
7507509ff7cSJens Wiklander 		for (n = 0; n < elf->e_shnum; n++)
7517509ff7cSJens Wiklander 			if (shdr[n].sh_type == SHT_RELA)
7527509ff7cSJens Wiklander 				e64_relocate(elf, n);
7537509ff7cSJens Wiklander 
7547509ff7cSJens Wiklander 	}
7557509ff7cSJens Wiklander }
756