未验证 提交 a54e5421 编写于 作者: O openharmony_ci 提交者: Gitee

!609 MUSL vdso api support

Merge pull request !609 from guzhihao4/vdso_refactor
......@@ -2010,6 +2010,7 @@ musl_inc_root_files = [
]
musl_src_porting_file = [
"arch/aarch64/syscall_arch.h",
"arch/arm/bits/fenv.h",
"arch/generic/bits/shm.h",
"arch/generic/crtbrand.s",
......@@ -2124,6 +2125,11 @@ musl_src_porting_file = [
"src/ldso/arm/dlvsym.s",
"src/ldso/riscv64/dlvsym.s",
"src/ldso/x86_64/dlvsym.s",
"src/internal/vdso.c",
"src/time/clock_gettime.c",
"src/time/clock_getres.c",
"src/time/gettimeofday.c",
"src/time/time.c",
]
musl_inc_hook_files = [
......
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define __SYSCALL_LL_E(x) (x)
#define __SYSCALL_LL_O(x) (x)
#define __asm_syscall(...) do { \
__asm__ __volatile__ ( "svc 0" \
: "=r"(x0) : __VA_ARGS__ : "memory", "cc"); \
return x0; \
} while (0)
static inline long __syscall0(long n)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0");
__asm_syscall("r"(x8));
}
static inline long __syscall1(long n, long a)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
__asm_syscall("r"(x8), "0"(x0));
}
static inline long __syscall2(long n, long a, long b)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
register long x1 __asm__("x1") = b;
__asm_syscall("r"(x8), "0"(x0), "r"(x1));
}
static inline long __syscall3(long n, long a, long b, long c)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
register long x1 __asm__("x1") = b;
register long x2 __asm__("x2") = c;
__asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2));
}
static inline long __syscall4(long n, long a, long b, long c, long d)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
register long x1 __asm__("x1") = b;
register long x2 __asm__("x2") = c;
register long x3 __asm__("x3") = d;
__asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3));
}
static inline long __syscall5(long n, long a, long b, long c, long d, long e)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
register long x1 __asm__("x1") = b;
register long x2 __asm__("x2") = c;
register long x3 __asm__("x3") = d;
register long x4 __asm__("x4") = e;
__asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4));
}
static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
register long x1 __asm__("x1") = b;
register long x2 __asm__("x2") = c;
register long x3 __asm__("x3") = d;
register long x4 __asm__("x4") = e;
register long x5 __asm__("x5") = f;
__asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5));
}
#define VDSO_USEFUL
#define VDSO_CGT_SYM "__kernel_clock_gettime"
#define VDSO_CGT_VER "LINUX_2.6.39"
#define VDSO_CGR_SYM "__kernel_clock_getres"
#define VDSO_CGR_VER "LINUX_2.6.39"
#define VDSO_GTD_SYM "__kernel_gettimeofday"
#define VDSO_GTD_VER "LINUX_2.6.39"
#define IPC_64 0
......@@ -377,4 +377,7 @@ hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned);
hidden void *__vdsosym(const char *, const char *);
hidden void __get_vdso_info();
hidden void *__get_vdso_addr(const char *, const char *);
#endif
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <elf.h>
#include <link.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include "libc.h"
#include "syscall.h"
#ifdef VDSO_USEFUL
#if ULONG_MAX == 0xffffffff
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Phdr Phdr;
typedef Elf32_Sym Sym;
typedef Elf32_Verdef Verdef;
typedef Elf32_Verdaux Verdaux;
#else
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Phdr Phdr;
typedef Elf64_Sym Sym;
typedef Elf64_Verdef Verdef;
typedef Elf64_Verdaux Verdaux;
#endif
static int checkver(Verdef *def, int vsym, const char *vername, char *strings)
{
vsym &= 0x7fff;
for (;;) {
if (!(def->vd_flags & VER_FLG_BASE)
&& (def->vd_ndx & 0x7fff) == vsym)
break;
if (def->vd_next == 0)
return 0;
def = (Verdef *)((char *)def + def->vd_next);
}
Verdaux *aux = (Verdaux *)((char *)def + def->vd_aux);
return !strcmp(vername, strings + aux->vda_name);
}
#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)
struct __vdso_info {
size_t base;
char *strings;
Sym *syms;
Elf_Symndx *hashtab;
uint16_t *versym;
Verdef *verdef;
} vdso_info = {-1, 0, 0, 0, 0, 0};
void __get_vdso_info()
{
if (vdso_info.base != -1) {
return ;
}
size_t i;
for (i=0; libc.auxv[i] != AT_SYSINFO_EHDR; i+=2)
if (!libc.auxv[i]) return ;
if (!libc.auxv[i+1]) return ;
Ehdr *eh = (void *)libc.auxv[i+1];
Phdr *ph = (void *)((char *)eh + eh->e_phoff);
size_t *dynv=0, base=-1;
for (i=0; i<eh->e_phnum; i++, ph=(void *)((char *)ph+eh->e_phentsize)) {
if (ph->p_type == PT_LOAD)
base = (size_t)eh + ph->p_offset - ph->p_vaddr;
else if (ph->p_type == PT_DYNAMIC)
dynv = (void *)((char *)eh + ph->p_offset);
}
if (!dynv || base==(size_t)-1) return ;
for (i=0; dynv[i]; i+=2) {
void *p = (void *)(base + dynv[i+1]);
switch(dynv[i]) {
case DT_STRTAB: vdso_info.strings = p; break;
case DT_SYMTAB: vdso_info.syms = p; break;
case DT_HASH: vdso_info.hashtab = p; break;
case DT_VERSYM: vdso_info.versym = p; break;
case DT_VERDEF: vdso_info.verdef = p; break;
}
}
vdso_info.base = base;
return ;
}
void *__get_vdso_addr(const char *vername, const char *name)
{
if (!vdso_info.strings || !vdso_info.syms || !vdso_info.hashtab) return 0;
if (!vdso_info.verdef) vdso_info.versym = 0;
size_t i;
for (i=0; i<vdso_info.hashtab[1]; i++) {
if (!(1<<(vdso_info.syms[i].st_info&0xf) & OK_TYPES)) continue;
if (!(1<<(vdso_info.syms[i].st_info>>4) & OK_BINDS)) continue;
if (!vdso_info.syms[i].st_shndx) continue;
if (strcmp(name, vdso_info.strings+vdso_info.syms[i].st_name)) continue;
if (vdso_info.versym && !checkver(vdso_info.verdef, vdso_info.versym[i], vername, vdso_info.strings))
continue;
return (void *)(vdso_info.base + vdso_info.syms[i].st_value);
}
return 0;
}
#endif
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include "syscall.h"
#include "atomic.h"
#ifdef VDSO_CGR_SYM
static void *volatile vdso_cgr;
static int cgr_init(clockid_t clk, struct timespec *ts)
{
__get_vdso_info();
void *p = __get_vdso_addr(VDSO_CGR_VER, VDSO_CGR_SYM);
int (*f)(clockid_t, struct timespec *) =
(int (*)(clockid_t, struct timespec *))p;
a_cas_p(&vdso_cgr, (void *)cgr_init, p);
return f ? f(clk, ts) : -ENOSYS;
}
static void *volatile vdso_cgr = (void *)cgr_init;
#endif
int clock_getres(clockid_t clk, struct timespec *ts)
{
int r;
#ifdef VDSO_CGR_SYM
int (*f)(clockid_t, struct timespec *) =
(int (*)(clockid_t, struct timespec *))vdso_cgr;
if (f) {
r = f(clk, ts);
if (!r) return r;
if (r == -EINVAL) return __syscall_ret(r);
}
#endif
#ifdef SYS_clock_getres_time64
/* On a 32-bit arch, use the old syscall if it exists. */
if (SYS_clock_getres != SYS_clock_getres_time64) {
long ts32[2];
r = __syscall(SYS_clock_getres, clk, ts32);
if (!r && ts) {
ts->tv_sec = ts32[0];
ts->tv_nsec = ts32[1];
}
return __syscall_ret(r);
}
#endif
/* If reaching this point, it's a 64-bit arch or time64-only
* 32-bit arch and we can get result directly into timespec. */
return syscall(SYS_clock_getres, clk, ts);
}
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include "syscall.h"
#include "atomic.h"
#ifdef VDSO_CGT_SYM
static void *volatile vdso_func;
#ifdef VDSO_CGT32_SYM
static void *volatile vdso_func_32;
static int cgt_time32_wrap(clockid_t clk, struct timespec *ts)
{
long ts32[2];
int (*f)(clockid_t, long[2]) =
(int (*)(clockid_t, long[2]))vdso_func_32;
int r = f(clk, ts32);
if (!r) {
/* Fallback to syscalls if time32 overflowed. Maybe
* we lucked out and somehow migrated to a kernel with
* time64 syscalls available. */
if (ts32[0] < 0) {
a_cas_p(&vdso_func, (void *)cgt_time32_wrap, 0);
return -ENOSYS;
}
ts->tv_sec = ts32[0];
ts->tv_nsec = ts32[1];
}
return r;
}
#endif
static int cgt_init(clockid_t clk, struct timespec *ts)
{
__get_vdso_info();
void *p = __get_vdso_addr(VDSO_CGT_VER, VDSO_CGT_SYM);
#ifdef VDSO_CGT32_SYM
if (!p) {
void *q = __get_vdso_addr(VDSO_CGT32_VER, VDSO_CGT32_SYM);
if (q) {
a_cas_p(&vdso_func_32, 0, q);
p = cgt_time32_wrap;
}
}
#endif
int (*f)(clockid_t, struct timespec *) =
(int (*)(clockid_t, struct timespec *))p;
a_cas_p(&vdso_func, (void *)cgt_init, p);
return f ? f(clk, ts) : -ENOSYS;
}
static void *volatile vdso_func = (void *)cgt_init;
#endif
int __clock_gettime(clockid_t clk, struct timespec *ts)
{
int r;
#ifdef VDSO_CGT_SYM
int (*f)(clockid_t, struct timespec *) =
(int (*)(clockid_t, struct timespec *))vdso_func;
if (f) {
r = f(clk, ts);
if (!r) return r;
if (r == -EINVAL) return __syscall_ret(r);
/* Fall through on errors other than EINVAL. Some buggy
* vdso implementations return ENOSYS for clocks they
* can't handle, rather than making the syscall. This
* also handles the case where cgt_init fails to find
* a vdso function to use. */
}
#endif
#ifdef SYS_clock_gettime64
r = -ENOSYS;
if (sizeof(time_t) > 4)
r = __syscall(SYS_clock_gettime64, clk, ts);
if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS)
return __syscall_ret(r);
long ts32[2];
r = __syscall(SYS_clock_gettime, clk, ts32);
if (r==-ENOSYS && clk==CLOCK_REALTIME) {
r = __syscall(SYS_gettimeofday, ts32, 0);
ts32[1] *= 1000;
}
if (!r) {
ts->tv_sec = ts32[0];
ts->tv_nsec = ts32[1];
return r;
}
return __syscall_ret(r);
#else
r = __syscall(SYS_clock_gettime, clk, ts);
if (r == -ENOSYS) {
if (clk == CLOCK_REALTIME) {
__syscall(SYS_gettimeofday, ts, 0);
ts->tv_nsec = (int)ts->tv_nsec * 1000;
return 0;
}
r = -EINVAL;
}
return __syscall_ret(r);
#endif
}
weak_alias(__clock_gettime, clock_gettime);
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <time.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include "syscall.h"
#include "atomic.h"
#ifdef VDSO_GTD_SYM
static void *volatile vdso_gtd;
static int gtd_init(struct timeval *tv, void *tz)
{
__get_vdso_info();
void *p = __get_vdso_addr(VDSO_GTD_VER, VDSO_GTD_SYM);
int (*f)(struct timeval *, void *) =
(int (*)(struct timval *, void *))p;
a_cas_p(&vdso_gtd, (void *)gtd_init, p);
return f ? f(tv, tz) : -ENOSYS;
}
static void *volatile vdso_gtd = (void *)gtd_init;
#endif
int gettimeofday(struct timeval *restrict tv, void *restrict tz)
{
#ifdef VDSO_GTD_SYM
int r;
int (*f)(struct timeval *, void *) =
(int (*)(struct timeval *, void *))vdso_gtd;
if (f) {
r = f(tv, tz);
if (!r) return r;
if (r == -EINVAL) return __syscall_ret(r);
}
#endif
struct timespec ts;
if (!tv) return 0;
clock_gettime(CLOCK_REALTIME, &ts);
tv->tv_sec = ts.tv_sec;
tv->tv_usec = (int)ts.tv_nsec / 1000;
return 0;
}
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include "syscall.h"
#include "atomic.h"
#ifdef VDSO_TIME_SYM
static void *volatile vdso_time;
static time_t time_init(time_t *t)
{
__get_vdso_info();
void *p = __get_vdso_addr(VDSO_TIME_VER, VDSO_TIME_SYM);
time_t (*f)(time_t *) =
(time_t (*)(time_t *))p;
a_cas_p(&vdso_time, (void *)time_init, p);
return f ? f(t) : -ENOSYS;
}
static void *volatile vdso_time = (void *)time_init;
#endif
time_t time(time_t *t)
{
#ifdef VDSO_TIME_SYM
time_t (*f)(time_t *) =
(time_t (*)(time_t *))vdso_time;
if (f) {
return f(t);
}
#endif
struct timespec ts;
__clock_gettime(CLOCK_REALTIME, &ts);
if (t) *t = ts.tv_sec;
return ts.tv_sec;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册