Make improvements

- Implement openpty()
- Add `--assimilate` flag to APE bootloader
- Restore Linux vDSO clock_gettime() support
- Use `$(APE_NO_MODIFY_SELF)` on more programs
This commit is contained in:
Justine Tunney 2022-05-24 10:19:39 -07:00
parent cef50f2a6b
commit d44ff6ce1f
33 changed files with 600 additions and 251 deletions

View file

@ -0,0 +1,30 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.initbss 201,_init___clock_gettime
__clock_gettime:
.quad 0
.endobj __clock_gettime,globl,hidden
.previous
.init.start 201,_init___clock_gettime
ezlea __clock_gettime_init,ax
stosq
.init.end 201,_init___clock_gettime

View file

@ -0,0 +1,19 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
#include "libc/bits/asmflag.h"
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
forceinline bool __asan_is_valid_timespec(const struct timespec *ts) {
bool zf;
asm(ZFLAG_ASM("cmpw\t$0,0x7fff8000(%1)")
: ZFLAG_CONSTRAINT(zf)
: "r"((intptr_t)ts >> 3)
: "memory");
return zf;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ */

View file

@ -27,6 +27,7 @@ textwindows int sys_clock_gettime_nt(int clockid, struct timespec *ts) {
struct timespec res;
struct NtFileTime ft;
static struct timespec mono;
if (!ts) return efault();
if (clockid == CLOCK_REALTIME) {
GetSystemTimeAsFileTime(&ft);
*ts = FileTimeToTimeSpec(ft);

View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
int sys_clock_gettime_xnu(int clockid, struct timespec *ts) {
axdx_t ad;
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
if (ad.ax != -1) {
if (ad.ax) {
ts->tv_sec = ad.ax;
ts->tv_nsec = ad.dx;
}
ts->tv_nsec *= 1000;
return 0;
} else {
return -1;
}
}

View file

@ -17,6 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/asmflag.h"
#include "libc/bits/bits.h"
#include "libc/calls/asan.internal.h"
#include "libc/calls/clock_gettime.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/strace.internal.h"
@ -26,11 +30,10 @@
#include "libc/fmt/conv.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
/**
* Returns nanosecond time.
*
@ -38,6 +41,13 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
* time. Among the more popular is CLOCK_MONOTONIC. This function has a
* zero syscall implementation of that on modern x86.
*
* nowl l: 45𝑐 15𝑛𝑠
* rdtsc l: 13𝑐 4𝑛𝑠
* gettimeofday l: 44𝑐 14𝑛𝑠
* clock_gettime l: 40𝑐 13𝑛𝑠
* __clock_gettime l: 35𝑐 11𝑛𝑠
* sys_clock_gettime l: 220𝑐 71𝑛𝑠
*
* @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc.
* @param ts is where the result is stored
* @return 0 on success, or -1 w/ errno
@ -46,54 +56,49 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
* @asyncsignalsafe
*/
noinstrument int clock_gettime(int clockid, struct timespec *ts) {
int rc, e;
axdx_t ad;
char buf[45];
if (!ts) {
int rc;
char *buf;
if (IsAsan() && !__asan_is_valid_timespec(ts)) {
rc = efault();
} else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
rc = efault();
} else if (clockid == -1) {
rc = einval();
} else if (!IsWindows()) {
e = errno;
if ((rc = __clock_gettime(clockid, ts))) {
errno = e;
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
assert(ad.ax != -1);
if (SupportsXnu() && ad.ax) {
ts->tv_sec = ad.ax;
ts->tv_nsec = ad.dx;
}
ts->tv_nsec *= 1000;
rc = 0;
}
} else {
rc = sys_clock_gettime_nt(clockid, ts);
rc = __clock_gettime(clockid, ts);
}
#if SYSDEBUG
if (!__time_critical) {
buf = alloca(45);
STRACE("clock_gettime(%d, [%s]) → %d% m", clockid,
DescribeTimespec(buf, sizeof(buf), rc, ts), rc);
DescribeTimespec(buf, 45, rc, ts), rc);
}
#endif
return rc;
}
/**
* Returns fast system clock_gettime() if it exists.
* Returns pointer to fastest clock_gettime().
*/
void *__get_clock_gettime(void) {
void *vdso;
static bool once;
static void *result;
if (!once) {
if ((vdso = __vdsofunc("__vdso_clock_gettime"))) {
__clock_gettime = result = vdso;
}
once = true;
clock_gettime_f *__get_clock_gettime(bool *opt_out_isfast) {
bool isfast;
clock_gettime_f *res;
if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_clock_gettime"))) {
isfast = true;
} else if (IsXnu()) {
isfast = false;
res = sys_clock_gettime_xnu;
} else if (IsWindows()) {
isfast = true;
res = sys_clock_gettime_nt;
} else {
isfast = false;
res = sys_clock_gettime;
}
return result;
if (opt_out_isfast) {
*opt_out_isfast = isfast;
}
return res;
}
const void *const __clock_gettime_ctor[] initarray = {
__get_clock_gettime,
};
hidden int __clock_gettime_init(int clockid, struct timespec *ts) {
clock_gettime_f *gettime;
__clock_gettime = gettime = __get_clock_gettime(0);
return gettime(clockid, ts);
}

View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_
#define COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef int clock_gettime_f(int, struct timespec *);
extern clock_gettime_f *__clock_gettime;
hidden clock_gettime_f __clock_gettime_init;
hidden clock_gettime_f *__get_clock_gettime(bool *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ */

View file

@ -59,7 +59,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
static textstartup void __gettimeofday_init(void) {
void *vdso;
if ((vdso = __vdsofunc("__vdso_gettimeofday"))) {
if ((vdso = __vdsosym("LINUX_2.6", "__vdso_gettimeofday"))) {
__gettimeofday = vdso;
}
}

View file

@ -118,6 +118,7 @@ i32 __sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden;
i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden;
i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden;
i32 sys_clock_gettime(i32, struct timespec *) hidden;
i32 sys_clock_gettime_xnu(i32, struct timespec *) hidden;
i32 sys_fstat(i32, struct stat *) hidden;
i32 sys_fstatat(i32, const char *, struct stat *, i32) hidden;
i32 sys_futimes(i32, const struct timeval *) hidden;

View file

@ -83,7 +83,7 @@ noasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
/**
* Sorts, rounds, and filters BIOS memory map.
*/
static noasan texthead void __normalize_e820(struct mman *mm) {
static noasan textreal void __normalize_e820(struct mman *mm) {
uint64_t a, b;
uint64_t x, y;
unsigned i, j, n;
@ -113,7 +113,7 @@ static noasan texthead void __normalize_e820(struct mman *mm) {
/**
* Identity maps all usable physical memory to its negative address.
*/
static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) {
static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) {
uint64_t i, j, *m, p, pe;
for (i = 0; i < mm->e820n; ++i) {
for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size;
@ -126,7 +126,7 @@ static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) {
}
}
noasan texthead void __setup_mman(struct mman *mm, uint64_t *pml4t) {
noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) {
__normalize_e820(mm);
__invert_memory(mm, pml4t);
}

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
@ -31,7 +32,8 @@
noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) {
int rc;
char buf[2][45];
if (!req) {
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
(rem && !__asan_is_valid_timespec(rem))))) {
rc = efault();
} else if (req->tv_sec < 0 ||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {

View file

@ -20,6 +20,7 @@
#include "libc/bits/initializer.internal.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/clock_gettime.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/strace.internal.h"
@ -32,10 +33,11 @@
#include "libc/sysv/consts/clock.h"
#include "libc/time/time.h"
static clock_gettime_f *__gettime;
static struct Now {
uint64_t k0;
long double r0, cpn;
typeof(sys_clock_gettime) *clock_gettime;
} g_now;
static long double GetTimeSample(void) {
@ -90,7 +92,7 @@ static long double nowl_art(void) {
static long double nowl_vdso(void) {
long double secs;
struct timespec tv;
g_now.clock_gettime(CLOCK_REALTIME, &tv);
__gettime(CLOCK_REALTIME, &tv);
secs = tv.tv_nsec;
secs *= 1 / 1e9L;
secs += tv.tv_sec;
@ -98,9 +100,10 @@ static long double nowl_vdso(void) {
}
long double nowl_setup(void) {
bool isfast;
uint64_t ticks;
if (0 && (g_now.clock_gettime = __get_clock_gettime())) {
// TODO(jart): Re-enable this.
__gettime = __get_clock_gettime(&isfast);
if (isfast) {
nowl = nowl_vdso;
} else if (X86_HAVE(INVTSC)) {
RefreshTime();

View file

@ -17,33 +17,44 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/termios.h"
#include "libc/fmt/itoa.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pty.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
/**
* Opens new pseudo teletypewriter.
*
* @param ilduce receives controlling tty rw fd on success
* @param aworker receives subordinate tty rw fd on success
* @param termp may be passed to tune a century of legacy behaviors
* @param winp may be passed to set terminal display dimensions
* @param mfd receives controlling tty rw fd on success
* @param sfd receives subordinate tty rw fd on success
* @param tio may be passed to tune a century of legacy behaviors
* @param wsz may be passed to set terminal display dimensions
* @params flags is usually O_RDWR|O_NOCTTY
* @return file descriptor, or -1 w/ errno
* @return 0 on success, or -1 w/ errno
*/
int openpty(int *ilduce, int *aworker, char *name, const struct termios *termp,
const struct winsize *winp) {
return enosys();
/* TODO(jart) */
/* int fd, flags; */
/* flags = O_RDWR | O_NOCTTY; */
/* if ((fd = posix_openpt(flags)) != -1) { */
/* if (ioctl(m, TIOCSPTLCK, &n) || ioctl(m, TIOCGPTN, &n)) { */
/* } else { */
/* close(fd); */
/* } */
/* } else { */
/* return -1; */
/* } */
int openpty(int *mfd, int *sfd, char *name, const struct termios *tio,
const struct winsize *wsz) {
int m, s, n;
char buf[20];
if ((m = open("/dev/ptmx", O_RDWR | O_NOCTTY)) != -1) {
n = 0;
if (!ioctl(m, TIOCSPTLCK, &n) || !ioctl(m, TIOCGPTN, &n)) {
if (!name) name = buf;
name[0] = '/', name[1] = 'd', name[2] = 'e', name[3] = 'v';
name[4] = '/', name[5] = 'p', name[6] = 't', name[7] = 's';
name[8] = '/', FormatInt32(name + 9, n);
if ((s = open(name, O_RDWR | O_NOCTTY)) != -1) {
if (tio) ioctl(s, TCSETS, tio);
if (wsz) ioctl(s, TIOCSWINSZ, wsz);
*mfd = m;
*sfd = s;
return 0;
}
}
close(m);
}
return -1;
}

View file

@ -12,8 +12,7 @@ int __notziposat(int, const char *);
int gethostname_bsd(char *, size_t) hidden;
int gethostname_linux(char *, size_t) hidden;
int gethostname_nt(char *, size_t, int) hidden;
void *__get_clock_gettime(void) hidden;
void *__vdsofunc(const char *) hidden;
void *__vdsosym(const char *, const char *) hidden;
void __onfork(void) hidden;
void __restore_rt() hidden;
void __restore_rt_netbsd(void) hidden;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/asan.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
@ -39,7 +40,8 @@ int utimensat(int dirfd, const char *path, const struct timespec ts[2],
int rc;
char buf[12];
if (IsAsan() && (!__asan_is_valid(path, 1) ||
(ts && !__asan_is_valid(ts, sizeof(struct timespec) * 2)))) {
(ts && (!__asan_is_valid_timespec(ts + 0) ||
!__asan_is_valid_timespec(ts + 1))))) {
rc = efault();
} else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) {
STRACE("zipos mkdirat not supported yet");

View file

@ -18,76 +18,136 @@
*/
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/elf/scalar.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/elf/struct/phdr.h"
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
#include "libc/log/libfatal.internal.h"
#include "libc/elf/struct/verdaux.h"
#include "libc/elf/struct/verdef.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#define LAZY_RHEL7_RELOCATION 0xfffff
#define GetStr(tab, rva) ((char *)(tab) + (rva))
#define GetSection(e, s) ((void *)((intptr_t)(e) + (size_t)(s)->sh_offset))
#define GetShstrtab(e) GetSection(e, GetShdr(e, (e)->e_shstrndx))
#define GetSectionName(e, s) GetStr(GetShstrtab(e), (s)->sh_name)
#define GetPhdr(e, i) \
((Elf64_Phdr *)((intptr_t)(e) + (e)->e_phoff + \
(size_t)(e)->e_phentsize * (i)))
#define GetShdr(e, i) \
((Elf64_Shdr *)((intptr_t)(e) + (e)->e_shoff + \
(size_t)(e)->e_shentsize * (i)))
static char *GetDynamicStringTable(Elf64_Ehdr *e, size_t *n) {
char *name;
Elf64_Half i;
Elf64_Shdr *shdr;
for (i = 0; i < e->e_shnum; ++i) {
shdr = GetShdr(e, i);
name = GetSectionName(e, GetShdr(e, i));
if (shdr->sh_type == SHT_STRTAB) {
name = GetSectionName(e, GetShdr(e, i));
if (name && READ64LE(name) == READ64LE(".dynstr")) {
if (n) *n = shdr->sh_size;
return GetSection(e, shdr);
}
}
}
return 0;
static inline int CompareStrings(const char *l, const char *r) {
size_t i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 255) - (r[i] & 255);
}
static Elf64_Sym *GetDynamicSymbolTable(Elf64_Ehdr *e, Elf64_Xword *n) {
Elf64_Half i;
Elf64_Shdr *shdr;
for (i = e->e_shnum; i > 0; --i) {
shdr = GetShdr(e, i - 1);
if (shdr->sh_type == SHT_DYNSYM) {
if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue;
if (n) *n = shdr->sh_size / shdr->sh_entsize;
return GetSection(e, shdr);
static inline int CheckDsoSymbolVersion(Elf64_Verdef *vd, int sym,
const char *name, char *strtab) {
Elf64_Verdaux *aux;
for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) {
if (!(vd->vd_flags & VER_FLG_BASE) &&
(vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) {
aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux);
return !CompareStrings(name, strtab + aux->vda_name);
}
if (!vd->vd_next) {
return 0;
}
}
return 0;
}
/**
* Returns Linux Kernel Virtual Dynamic Shared Object function address.
* Returns address of vDSO function.
*/
void *__vdsofunc(const char *name) {
size_t m;
char *names;
void *__vdsosym(const char *version, const char *name) {
void *p;
size_t i;
Elf64_Ehdr *ehdr;
Elf64_Xword i, n;
Elf64_Sym *symtab, *sym;
if ((ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR)) &&
(names = GetDynamicStringTable(ehdr, &m)) &&
(symtab = GetDynamicSymbolTable(ehdr, &n))) {
for (i = 0; i < n; ++i) {
if (!__strcmp(names + symtab[i].st_name, name)) {
return (char *)ehdr + (symtab[i].st_value & LAZY_RHEL7_RELOCATION);
}
Elf64_Phdr *phdr;
char *strtab = 0;
size_t *dyn, base;
unsigned long *ap;
Elf64_Sym *symtab = 0;
uint16_t *versym = 0;
Elf_Symndx *hashtab = 0;
Elf64_Verdef *verdef = 0;
for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) {
if (ap[0] == AT_SYSINFO_EHDR) {
ehdr = (void *)ap[1];
break;
}
}
if (!ehdr || READ32LE(ehdr->e_ident) != READ32LE("\177ELF")) {
KERNTRACE("__vdsosym() → AT_SYSINFO_EHDR ELF not found");
return 0;
}
phdr = (void *)((char *)ehdr + ehdr->e_phoff);
for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum;
i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) {
switch (phdr->p_type) {
case PT_LOAD:
// modern linux uses the base address zero, but elders
// e.g. rhel7 uses the base address 0xffffffffff700000
base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr;
break;
case PT_DYNAMIC:
dyn = (void *)((char *)ehdr + phdr->p_offset);
break;
default:
break;
}
}
if (!dyn || base == -1) {
KERNTRACE("__vdsosym() → missing program headers");
return 0;
}
for (i = 0; dyn[i]; i += 2) {
p = (void *)(base + dyn[i + 1]);
switch (dyn[i]) {
case DT_STRTAB:
strtab = p;
break;
case DT_SYMTAB:
symtab = p;
break;
case DT_HASH:
hashtab = p;
break;
case DT_VERSYM:
versym = p;
break;
case DT_VERDEF:
verdef = p;
break;
}
}
if (!strtab || !symtab || !hashtab) {
KERNTRACE("__vdsosym() → tables not found");
return 0;
}
if (!verdef) {
versym = 0;
}
for (i = 0; i < hashtab[1]; i++) {
if (ELF64_ST_TYPE(symtab[i].st_info) != STT_FUNC &&
ELF64_ST_TYPE(symtab[i].st_info) != STT_OBJECT &&
ELF64_ST_TYPE(symtab[i].st_info) != STT_NOTYPE) {
continue;
}
if (ELF64_ST_BIND(symtab[i].st_info) != STB_GLOBAL) {
continue;
}
if (!symtab[i].st_shndx) {
continue;
}
if (CompareStrings(name, strtab + symtab[i].st_name)) {
continue;
}
if (versym && !CheckDsoSymbolVersion(verdef, versym[i], version, strtab)) {
continue;
}
return (void *)(base + symtab[i].st_value);
}
KERNTRACE("__vdsosym() → symbol not found");
return 0;
}