diff options
Diffstat (limited to 'lib/libc/arch/x86_64/vdso_setup.c')
| -rw-r--r-- | lib/libc/arch/x86_64/vdso_setup.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/lib/libc/arch/x86_64/vdso_setup.c b/lib/libc/arch/x86_64/vdso_setup.c new file mode 100644 index 00000000..c410995d --- /dev/null +++ b/lib/libc/arch/x86_64/vdso_setup.c @@ -0,0 +1,62 @@ +#include <linux/auxvec.h> +#include <linux/elf.h> +#include <string.h> +#include <time.h> + +int (*__vdso_clock_gettime)(int, struct timespec *) = NULL; +int (*__vdso_getcpu)(unsigned *, unsigned *, void *) = NULL; +int (*__vdso_time)(long *) = NULL; + +static __inline __attribute__((used)) void vdso_setup(Elf64_Ehdr *vdso_addr) +{ + Elf64_Phdr *phdr = + (Elf64_Phdr *)((char *)vdso_addr + vdso_addr->e_phoff); + + for (int i = 0; i < vdso_addr->e_phnum; i++) { + if (phdr[i].p_type == PT_DYNAMIC) { + Elf64_Dyn *dyn = (Elf64_Dyn *)((char *)vdso_addr + + phdr[i].p_offset); + const char *strtab = NULL; + Elf64_Sym *symtab = NULL; + for (; dyn->d_tag != DT_NULL; dyn++) { + if (dyn->d_tag == DT_STRTAB) { + strtab = (const char *)vdso_addr + + dyn->d_un.d_ptr; + } else if (dyn->d_tag == DT_SYMTAB) { + symtab = + (Elf64_Sym *)((char *)vdso_addr + + dyn->d_un.d_ptr); + } + } + + if (strtab == NULL || symtab == NULL) { + return; + } + + Elf64_Sym *sym = symtab; + while ((char *)sym < (char *)strtab) { + if (sym->st_name != 0 && sym->st_value != 0) { + const char *name = + strtab + sym->st_name; + if (strcmp(name, + "__vdso_clock_gettime") == 0) + __vdso_clock_gettime = + (void *)(vdso_addr + + sym->st_value); + else if (strcmp(name, + "__vdso_getcpu") == 0) + __vdso_getcpu = + (void *)(vdso_addr + + sym->st_value); + else if (strcmp(name, "__vdso_time") == + 0) + __vdso_time = + (void *)(vdso_addr + + sym->st_value); + } + sym = (Elf64_Sym *)((char *)sym + + sizeof(Elf64_Sym)); + } + } + } +} |
