diff options
Diffstat (limited to 'src/ldso/arm')
-rw-r--r-- | src/ldso/arm/dlsym.s | 8 | ||||
-rw-r--r-- | src/ldso/arm/dlsym_time64.S | 3 | ||||
-rw-r--r-- | src/ldso/arm/find_exidx.c | 42 | ||||
-rw-r--r-- | src/ldso/arm/tlsdesc.S | 55 |
4 files changed, 108 insertions, 0 deletions
diff --git a/src/ldso/arm/dlsym.s b/src/ldso/arm/dlsym.s new file mode 100644 index 0000000..2652c34 --- /dev/null +++ b/src/ldso/arm/dlsym.s @@ -0,0 +1,8 @@ +.syntax unified +.text +.global dlsym +.hidden __dlsym +.type dlsym,%function +dlsym: + mov r2,lr + b __dlsym diff --git a/src/ldso/arm/dlsym_time64.S b/src/ldso/arm/dlsym_time64.S new file mode 100644 index 0000000..bb2e704 --- /dev/null +++ b/src/ldso/arm/dlsym_time64.S @@ -0,0 +1,3 @@ +#define __dlsym __dlsym_redir_time64 +#define dlsym __dlsym_time64 +#include "dlsym.s" diff --git a/src/ldso/arm/find_exidx.c b/src/ldso/arm/find_exidx.c new file mode 100644 index 0000000..77c4472 --- /dev/null +++ b/src/ldso/arm/find_exidx.c @@ -0,0 +1,42 @@ +#define _GNU_SOURCE +#include <link.h> +#include <stdint.h> + +struct find_exidx_data { + uintptr_t pc, exidx_start; + int exidx_len; +}; + +static int find_exidx(struct dl_phdr_info *info, size_t size, void *ptr) +{ + struct find_exidx_data *data = ptr; + const ElfW(Phdr) *phdr = info->dlpi_phdr; + uintptr_t addr, exidx_start = 0; + int i, match = 0, exidx_len = 0; + + for (i = info->dlpi_phnum; i > 0; i--, phdr++) { + addr = info->dlpi_addr + phdr->p_vaddr; + switch (phdr->p_type) { + case PT_LOAD: + match |= data->pc >= addr && data->pc < addr + phdr->p_memsz; + break; + case PT_ARM_EXIDX: + exidx_start = addr; + exidx_len = phdr->p_memsz; + break; + } + } + data->exidx_start = exidx_start; + data->exidx_len = exidx_len; + return match; +} + +uintptr_t __gnu_Unwind_Find_exidx(uintptr_t pc, int *pcount) +{ + struct find_exidx_data data; + data.pc = pc; + if (dl_iterate_phdr(find_exidx, &data) <= 0) + return 0; + *pcount = data.exidx_len / 8; + return data.exidx_start; +} diff --git a/src/ldso/arm/tlsdesc.S b/src/ldso/arm/tlsdesc.S new file mode 100644 index 0000000..3ae133c --- /dev/null +++ b/src/ldso/arm/tlsdesc.S @@ -0,0 +1,55 @@ +.syntax unified + +.text +.global __tlsdesc_static +.hidden __tlsdesc_static +.type __tlsdesc_static,%function +__tlsdesc_static: + ldr r0,[r0] + bx lr + +.global __tlsdesc_dynamic +.hidden __tlsdesc_dynamic +.type __tlsdesc_dynamic,%function +__tlsdesc_dynamic: + push {r2,r3,ip,lr} + ldr r1,[r0] + ldr r2,[r1,#4] // r2 = offset + ldr r1,[r1] // r1 = modid + +#if ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ + || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7 + mrc p15,0,r0,c13,c0,3 +#else + ldr r0,1f + add r0,r0,pc + ldr r0,[r0] +2: +#if __ARM_ARCH >= 5 + blx r0 // r0 = tp +#else +#if __thumb__ + add lr,pc,#1 +#else + mov lr,pc +#endif + bx r0 +#endif +#endif + ldr r3,[r0,#-4] // r3 = dtv + ldr ip,[r3,r1,LSL #2] + sub r0,ip,r0 + add r0,r0,r2 // r0 = r3[r1]-r0+r2 +#if __ARM_ARCH >= 5 + pop {r2,r3,ip,pc} +#else + pop {r2,r3,ip,lr} + bx lr +#endif + +#if ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \ + || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7 +#else + .align 2 +1: .word __a_gettp_ptr - 2b +#endif |