diff options
author | Jerome Forissier <jerome@forissier.org> | 2020-07-21 10:54:55 +0200 |
---|---|---|
committer | Jérôme Forissier <jerome@forissier.org> | 2020-08-06 11:10:44 +0200 |
commit | cf830b2b674ccc672d0124425714da7cae27c303 (patch) | |
tree | b6ce35adad7450a0873a820fa498040c55c70a9e | |
parent | 405a5072d8bd25c18fd151d97e452d6863786f03 (diff) |
ldelf: add support for weak symbols
Preparing for C++ support in TAs.
When ldelf performs a symbol lookup in a TA, it currently considers
only global symbols that are not undefined. It turns out that g++ can
generates dynamic relocations referencing symbols that are weak and
undefined [1], in other words: weak declarations. Those should end up
resolving to zero.
This commit updates the symbol resolution to first look for global
defined symbols, then weak defined, then weak undefined.
[1] __pthread_key_create, pthread_mutex_lock, pthread_mutex_unlock,
__gnu_Unwind_Find_exidx.
Signed-off-by: Jerome Forissier <jerome@forissier.org>
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r-- | ldelf/ta_elf_rel.c | 54 |
1 files changed, 41 insertions, 13 deletions
diff --git a/ldelf/ta_elf_rel.c b/ldelf/ta_elf_rel.c index 782d1682..3822f4c7 100644 --- a/ldelf/ta_elf_rel.c +++ b/ldelf/ta_elf_rel.c @@ -35,19 +35,27 @@ static uint32_t elf_hash(const char *name) static bool __resolve_sym(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) + vaddr_t *val, bool weak_ok) { - if (st_bind != STB_GLOBAL) - return false; - if (st_shndx == SHN_UNDEF || st_shndx == SHN_XINDEX) - return false; + bool bind_ok = false; + if (!st_name) return false; if (st_name > elf->dynstr_size) err(TEE_ERROR_BAD_FORMAT, "Symbol name out of range"); - if (strcmp(name, elf->dynstr + st_name)) return false; + if (st_bind == STB_GLOBAL || (weak_ok && st_bind == STB_WEAK)) + bind_ok = true; + if (!bind_ok) + return false; + if (st_bind == STB_WEAK && st_shndx == SHN_UNDEF) { + if (val) + *val = 0; + return true; + } + if (st_shndx == SHN_UNDEF || st_shndx == SHN_XINDEX) + return false; if (st_value > (elf->max_addr - elf->load_addr)) err(TEE_ERROR_BAD_FORMAT, "Symbol location out of range"); @@ -66,7 +74,8 @@ static bool __resolve_sym(struct ta_elf *elf, unsigned int st_bind, } static TEE_Result resolve_sym_helper(uint32_t hash, const char *name, - vaddr_t *val, struct ta_elf *elf) + vaddr_t *val, struct ta_elf *elf, + bool weak_ok) { /* * Using uint32_t here for convenience because both Elf64_Word @@ -98,7 +107,7 @@ static TEE_Result resolve_sym_helper(uint32_t hash, const char *name, ELF32_ST_TYPE(sym[n].st_info), sym[n].st_shndx, sym[n].st_name, - sym[n].st_value, name, val)) + sym[n].st_value, name, val, weak_ok)) return TEE_SUCCESS; } } else { @@ -120,7 +129,7 @@ static TEE_Result resolve_sym_helper(uint32_t hash, const char *name, ELF64_ST_TYPE(sym[n].st_info), sym[n].st_shndx, sym[n].st_name, - sym[n].st_value, name, val)) + sym[n].st_value, name, val, weak_ok)) return TEE_SUCCESS; } } @@ -128,17 +137,36 @@ static TEE_Result resolve_sym_helper(uint32_t hash, const char *name, return TEE_ERROR_ITEM_NOT_FOUND; } +/* + * Look for named symbol in @elf, or all modules if @elf == NULL. Global symbols + * are searched first, then weak ones. Last option, when at least one weak but + * undefined symbol exists, resolve to zero. Otherwise return + * TEE_ERROR_ITEM_NOT_FOUND. + */ TEE_Result ta_elf_resolve_sym(const char *name, vaddr_t *val, struct ta_elf *elf) { uint32_t hash = elf_hash(name); - if (elf) - return resolve_sym_helper(hash, name, val, elf); + if (elf) { + /* Search global symbols */ + if (!resolve_sym_helper(hash, name, val, elf, + false /* !weak_ok */)) + return TEE_SUCCESS; + /* Search weak symbols */ + if (!resolve_sym_helper(hash, name, val, elf, + true /* weak_ok */)) + return TEE_SUCCESS; + } - TAILQ_FOREACH(elf, &main_elf_queue, link) - if (!resolve_sym_helper(hash, name, val, elf)) + TAILQ_FOREACH(elf, &main_elf_queue, link) { + if (!resolve_sym_helper(hash, name, val, elf, + false /* !weak_ok */)) return TEE_SUCCESS; + if (!resolve_sym_helper(hash, name, val, elf, + true /* weak_ok */)) + return TEE_SUCCESS; + } return TEE_ERROR_ITEM_NOT_FOUND; } |