1625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes/* 2625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Copyright (C) 2014 The Android Open Source Project 3625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * 4625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 5625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * you may not use this file except in compliance with the License. 6625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * You may obtain a copy of the License at 7625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * 8625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 9625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * 10625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Unless required by applicable law or agreed to in writing, software 11625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 12625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * See the License for the specific language governing permissions and 14625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * limitations under the License. 15625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes */ 16625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 1793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/bionic_globals.h" 1893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/bionic_vdso.h" 19625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 204ce902c30e087f45c6d6ede2012519e2eea44194Elliott Hughes#if defined(__aarch64__) || defined(__arm__) || defined(__i386__) || defined(__x86_64__) 21625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 22613f8145087a763e128d58e638bc85799fb06989Elliott Hughes#include <limits.h> 2393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <link.h> 2493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <string.h> 2593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <sys/cdefs.h> 2693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <sys/time.h> 27625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#include <time.h> 2893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <unistd.h> 2993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/KernelArgumentBlock.h" 30625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 314ce902c30e087f45c6d6ede2012519e2eea44194Elliott Hughes#define AT_SYSINFO_EHDR 33 /* until we have new enough uapi headers... */ 324ce902c30e087f45c6d6ede2012519e2eea44194Elliott Hughes 33625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesint clock_gettime(int clock_id, timespec* tp) { 3493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao auto vdso_clock_gettime = reinterpret_cast<decltype(&clock_gettime)>( 3593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao __libc_globals->vdso[VDSO_CLOCK_GETTIME].fn); 3693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao if (__predict_true(vdso_clock_gettime)) { 3793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao return vdso_clock_gettime(clock_id, tp); 3893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 3993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao return __clock_gettime(clock_id, tp); 40625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes} 41625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 42625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesint gettimeofday(timeval* tv, struct timezone* tz) { 4393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao auto vdso_gettimeofday = reinterpret_cast<decltype(&gettimeofday)>( 4493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao __libc_globals->vdso[VDSO_GETTIMEOFDAY].fn); 4593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao if (__predict_true(vdso_gettimeofday)) { 4693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao return vdso_gettimeofday(tv, tz); 4793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 4893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao return __gettimeofday(tv, tz); 49625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes} 50625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 5193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaovoid __libc_init_vdso(libc_globals* globals, KernelArgumentBlock& args) { 5293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao auto&& vdso = globals->vdso; 5393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao vdso[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, 5493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao reinterpret_cast<void*>(__clock_gettime) }; 5593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao vdso[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, 5693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao reinterpret_cast<void*>(__gettimeofday) }; 5793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 58625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // Do we have a vdso? 5993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao uintptr_t vdso_ehdr_addr = args.getauxval(AT_SYSINFO_EHDR); 60625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr); 61613f8145087a763e128d58e638bc85799fb06989Elliott Hughes if (vdso_ehdr == nullptr) { 62625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return; 63625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 64625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 65625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // How many symbols does it have? 66625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes size_t symbol_count = 0; 67625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes ElfW(Shdr)* vdso_shdr = reinterpret_cast<ElfW(Shdr)*>(vdso_ehdr_addr + vdso_ehdr->e_shoff); 68625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (size_t i = 0; i < vdso_ehdr->e_shnum; ++i) { 69625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes if (vdso_shdr[i].sh_type == SHT_DYNSYM) { 70625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes symbol_count = vdso_shdr[i].sh_size / sizeof(ElfW(Sym)); 71625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 72625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 73625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes if (symbol_count == 0) { 74625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return; 75625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 76625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 77625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // Where's the dynamic table? 78625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes ElfW(Addr) vdso_addr = 0; 79613f8145087a763e128d58e638bc85799fb06989Elliott Hughes ElfW(Dyn)* vdso_dyn = nullptr; 80625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes ElfW(Phdr)* vdso_phdr = reinterpret_cast<ElfW(Phdr)*>(vdso_ehdr_addr + vdso_ehdr->e_phoff); 81625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) { 82625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes if (vdso_phdr[i].p_type == PT_DYNAMIC) { 83625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes vdso_dyn = reinterpret_cast<ElfW(Dyn)*>(vdso_ehdr_addr + vdso_phdr[i].p_offset); 84625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } else if (vdso_phdr[i].p_type == PT_LOAD) { 85625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr; 86625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 87625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 88613f8145087a763e128d58e638bc85799fb06989Elliott Hughes if (vdso_addr == 0 || vdso_dyn == nullptr) { 89625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return; 90625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 91625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 92625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // Where are the string and symbol tables? 93613f8145087a763e128d58e638bc85799fb06989Elliott Hughes const char* strtab = nullptr; 94613f8145087a763e128d58e638bc85799fb06989Elliott Hughes ElfW(Sym)* symtab = nullptr; 95625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) { 96625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes if (d->d_tag == DT_STRTAB) { 97625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes strtab = reinterpret_cast<const char*>(vdso_addr + d->d_un.d_ptr); 98625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } else if (d->d_tag == DT_SYMTAB) { 99625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes symtab = reinterpret_cast<ElfW(Sym)*>(vdso_addr + d->d_un.d_ptr); 100625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 101625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 102613f8145087a763e128d58e638bc85799fb06989Elliott Hughes if (strtab == nullptr || symtab == nullptr) { 103625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return; 104625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 105625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 106625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // Are there any symbols we want? 107625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (size_t i = 0; i < symbol_count; ++i) { 108625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (size_t j = 0; j < VDSO_END; ++j) { 10993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao if (strcmp(vdso[j].name, strtab + symtab[i].st_name) == 0) { 11093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao vdso[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value); 111625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 112625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 113625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 114625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes} 115625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 116625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#else 117625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 11893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaovoid __libc_init_vdso(libc_globals*, KernelArgumentBlock&) { 119625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes} 120625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 121625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#endif 122