1 // SPDX-License-Identifier: GPL-2.0-only
3 * vdso_test.c: Sample code to test parse_vdso.c on x86
4 * Copyright (c) 2011-2014 Andy Lutomirski
6 * You can amuse yourself by compiling with:
7 * gcc -std=gnu99 -nostdlib
8 * -Os -fno-asynchronous-unwind-tables -flto -lgcc_s
9 * vdso_standalone_test_x86.c parse_vdso.c
10 * to generate a small binary. On x86_64, you can omit -lgcc_s
11 * if you want the binary to be completely standalone.
14 #include <sys/syscall.h>
19 extern void *vdso_sym(const char *version
, const char *name
);
20 extern void vdso_init_from_sysinfo_ehdr(uintptr_t base
);
21 extern void vdso_init_from_auxv(void *auxv
);
23 /* We need a libc functions... */
24 int strcmp(const char *a
, const char *b
)
26 /* This implementation is buggy: it never returns -1. */
30 if (*a
== 0 || *b
== 0)
39 /* ...and two syscalls. This is x86-specific. */
40 static inline long x86_syscall3(long nr
, long a0
, long a1
, long a2
)
44 asm volatile ("syscall" : "=a" (ret
) : "a" (nr
),
45 "D" (a0
), "S" (a1
), "d" (a2
) :
46 "cc", "memory", "rcx",
47 "r8", "r9", "r10", "r11" );
49 asm volatile ("int $0x80" : "=a" (ret
) : "a" (nr
),
50 "b" (a0
), "c" (a1
), "d" (a2
) :
56 static inline long linux_write(int fd
, const void *data
, size_t len
)
58 return x86_syscall3(__NR_write
, fd
, (long)data
, (long)len
);
61 static inline void linux_exit(int code
)
63 x86_syscall3(__NR_exit
, code
, 0, 0);
66 void to_base10(char *lastdig
, time_t n
)
69 *lastdig
= (n
% 10) + '0';
75 __attribute__((externally_visible
)) void c_main(void **stack
)
78 long argc
= (long)*stack
;
81 /* Now we're pointing at the environment. Skip it. */
86 /* Now we're pointing at auxv. Initialize the vDSO parser. */
87 vdso_init_from_auxv((void *)stack
);
89 /* Find gettimeofday. */
90 typedef long (*gtod_t
)(struct timeval
*tv
, struct timezone
*tz
);
91 gtod_t gtod
= (gtod_t
)vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
97 long ret
= gtod(&tv
, 0);
100 char buf
[] = "The time is .000000\n";
101 to_base10(buf
+ 31, tv
.tv_sec
);
102 to_base10(buf
+ 38, tv
.tv_usec
);
103 linux_write(1, buf
, sizeof(buf
) - 1);
112 * This is the real entry point. It passes the initial stack into
118 ".type _start,@function\n"