13002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes/*
23002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * Copyright (C) 2014 The Android Open Source Project
33002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes *
43002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
53002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * you may not use this file except in compliance with the License.
63002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * You may obtain a copy of the License at
73002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes *
83002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
93002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes *
103002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * Unless required by applicable law or agreed to in writing, software
113002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
123002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * See the License for the specific language governing permissions and
143002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes * limitations under the License.
153002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes */
163002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
173002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#include <link.h>
183002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#include <sys/auxv.h>
193002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#include <unistd.h>
203002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
213002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes// x86 has a vdso, but there's nothing useful to us in it.
223002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#if defined(__aarch64__) || defined(__x86_64__)
233002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
243002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#if defined(__aarch64__)
253002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
263002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#define VDSO_GETTIMEOFDAY_SYMBOL  "__kernel_gettimeofday"
273002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#elif defined(__x86_64__)
283002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
293002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#define VDSO_GETTIMEOFDAY_SYMBOL  "__vdso_gettimeofday"
303002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#endif
313002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
323002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#include <time.h>
333002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
343002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesextern "C" int __clock_gettime(int, timespec*);
353002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesextern "C" int __gettimeofday(timeval*, struct timezone*);
363002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
373002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesstruct vdso_entry {
383002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  const char* name;
393002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  void* fn;
403002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes};
413002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
423002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesenum {
433002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  VDSO_CLOCK_GETTIME = 0,
443002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  VDSO_GETTIMEOFDAY,
453002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  VDSO_END
463002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes};
473002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
483002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesstatic vdso_entry vdso_entries[] = {
493002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  [VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, reinterpret_cast<void*>(__clock_gettime) },
503002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  [VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, reinterpret_cast<void*>(__gettimeofday) },
513002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes};
523002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
533002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesint clock_gettime(int clock_id, timespec* tp) {
543002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  static int (*vdso_clock_gettime)(int, timespec*) =
553002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      (int (*)(int, timespec*)) vdso_entries[VDSO_CLOCK_GETTIME].fn;
563002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  return vdso_clock_gettime(clock_id, tp);
573002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes}
583002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
593002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesint gettimeofday(timeval* tv, struct timezone* tz) {
603002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  static int (*vdso_gettimeofday)(timeval*, struct timezone*) =
613002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      (int (*)(timeval*, struct timezone*)) vdso_entries[VDSO_GETTIMEOFDAY].fn;
623002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  return vdso_gettimeofday(tv, tz);
633002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes}
643002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
653002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesvoid __libc_init_vdso() {
663002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  // Do we have a vdso?
673002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR);
683002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr);
693002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  if (vdso_ehdr == NULL) {
703002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    return;
713002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
723002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
733002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  // How many symbols does it have?
743002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  size_t symbol_count = 0;
753002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  ElfW(Shdr)* vdso_shdr = reinterpret_cast<ElfW(Shdr)*>(vdso_ehdr_addr + vdso_ehdr->e_shoff);
763002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  for (size_t i = 0; i < vdso_ehdr->e_shnum; ++i) {
773002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    if (vdso_shdr[i].sh_type == SHT_DYNSYM) {
783002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      symbol_count = vdso_shdr[i].sh_size / sizeof(ElfW(Sym));
793002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    }
803002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
813002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  if (symbol_count == 0) {
823002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    return;
833002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
843002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
853002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  // Where's the dynamic table?
863002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  ElfW(Addr) vdso_addr = 0;
873002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  ElfW(Dyn)* vdso_dyn = NULL;
883002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  ElfW(Phdr)* vdso_phdr = reinterpret_cast<ElfW(Phdr)*>(vdso_ehdr_addr + vdso_ehdr->e_phoff);
893002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) {
903002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    if (vdso_phdr[i].p_type == PT_DYNAMIC) {
913002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      vdso_dyn = reinterpret_cast<ElfW(Dyn)*>(vdso_ehdr_addr + vdso_phdr[i].p_offset);
923002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    } else if (vdso_phdr[i].p_type == PT_LOAD) {
933002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr;
943002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    }
953002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
963002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  if (vdso_addr == 0 || vdso_dyn == NULL) {
973002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    return;
983002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
993002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
1003002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  // Where are the string and symbol tables?
1013002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  const char* strtab = NULL;
1023002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  ElfW(Sym)* symtab = NULL;
1033002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) {
1043002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    if (d->d_tag == DT_STRTAB) {
1053002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      strtab = reinterpret_cast<const char*>(vdso_addr + d->d_un.d_ptr);
1063002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    } else if (d->d_tag == DT_SYMTAB) {
1073002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      symtab = reinterpret_cast<ElfW(Sym)*>(vdso_addr + d->d_un.d_ptr);
1083002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    }
1093002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
1103002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  if (strtab == NULL || symtab == NULL) {
1113002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    return;
1123002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
1133002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
1143002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  // Are there any symbols we want?
1153002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  for (size_t i = 0; i < symbol_count; ++i) {
1163002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    for (size_t j = 0; j < VDSO_END; ++j) {
1173002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      if (strcmp(vdso_entries[j].name, strtab + symtab[i].st_name) == 0) {
1183002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes        vdso_entries[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value);
1193002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes      }
1203002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes    }
1213002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes  }
1223002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes}
1233002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
1243002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#else
1253002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
1263002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughesvoid __libc_init_vdso() {
1273002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes}
1283002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes
1293002131da33401cf1b45abbdbec58b7c751fc43aElliott Hughes#endif
130