Commit | Line | Data |
---|---|---|
98eedc3a | 1 | /* |
4ebbefd6 AL |
2 | * vdso_test.c: Sample code to test parse_vdso.c on x86 |
3 | * Copyright (c) 2011-2014 Andy Lutomirski | |
98eedc3a AL |
4 | * Subject to the GNU General Public License, version 2 |
5 | * | |
6 | * You can amuse yourself by compiling with: | |
7 | * gcc -std=gnu99 -nostdlib | |
4ebbefd6 | 8 | * -Os -fno-asynchronous-unwind-tables -flto -lgcc_s |
6e8f2158 | 9 | * vdso_standalone_test_x86.c parse_vdso.c |
4ebbefd6 AL |
10 | * to generate a small binary. On x86_64, you can omit -lgcc_s |
11 | * if you want the binary to be completely standalone. | |
98eedc3a AL |
12 | */ |
13 | ||
14 | #include <sys/syscall.h> | |
15 | #include <sys/time.h> | |
16 | #include <unistd.h> | |
17 | #include <stdint.h> | |
18 | ||
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); | |
22 | ||
23 | /* We need a libc functions... */ | |
24 | int strcmp(const char *a, const char *b) | |
25 | { | |
26 | /* This implementation is buggy: it never returns -1. */ | |
27 | while (*a || *b) { | |
28 | if (*a != *b) | |
29 | return 1; | |
30 | if (*a == 0 || *b == 0) | |
31 | return 1; | |
32 | a++; | |
33 | b++; | |
34 | } | |
35 | ||
36 | return 0; | |
37 | } | |
38 | ||
4ebbefd6 AL |
39 | /* ...and two syscalls. This is x86-specific. */ |
40 | static inline long x86_syscall3(long nr, long a0, long a1, long a2) | |
98eedc3a | 41 | { |
98eedc3a | 42 | long ret; |
4ebbefd6 AL |
43 | #ifdef __x86_64__ |
44 | asm volatile ("syscall" : "=a" (ret) : "a" (nr), | |
45 | "D" (a0), "S" (a1), "d" (a2) : | |
98eedc3a AL |
46 | "cc", "memory", "rcx", |
47 | "r8", "r9", "r10", "r11" ); | |
4ebbefd6 AL |
48 | #else |
49 | asm volatile ("int $0x80" : "=a" (ret) : "a" (nr), | |
50 | "b" (a0), "c" (a1), "d" (a2) : | |
51 | "cc", "memory" ); | |
52 | #endif | |
98eedc3a AL |
53 | return ret; |
54 | } | |
55 | ||
4ebbefd6 AL |
56 | static inline long linux_write(int fd, const void *data, size_t len) |
57 | { | |
58 | return x86_syscall3(__NR_write, fd, (long)data, (long)len); | |
59 | } | |
60 | ||
98eedc3a AL |
61 | static inline void linux_exit(int code) |
62 | { | |
4ebbefd6 | 63 | x86_syscall3(__NR_exit, code, 0, 0); |
98eedc3a AL |
64 | } |
65 | ||
16796892 | 66 | void to_base10(char *lastdig, time_t n) |
98eedc3a AL |
67 | { |
68 | while (n) { | |
69 | *lastdig = (n % 10) + '0'; | |
70 | n /= 10; | |
71 | lastdig--; | |
72 | } | |
73 | } | |
74 | ||
75 | __attribute__((externally_visible)) void c_main(void **stack) | |
76 | { | |
77 | /* Parse the stack */ | |
78 | long argc = (long)*stack; | |
79 | stack += argc + 2; | |
80 | ||
81 | /* Now we're pointing at the environment. Skip it. */ | |
82 | while(*stack) | |
83 | stack++; | |
84 | stack++; | |
85 | ||
86 | /* Now we're pointing at auxv. Initialize the vDSO parser. */ | |
87 | vdso_init_from_auxv((void *)stack); | |
88 | ||
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"); | |
92 | ||
93 | if (!gtod) | |
94 | linux_exit(1); | |
95 | ||
96 | struct timeval tv; | |
97 | long ret = gtod(&tv, 0); | |
98 | ||
99 | if (ret == 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); | |
104 | } else { | |
105 | linux_exit(ret); | |
106 | } | |
107 | ||
108 | linux_exit(0); | |
109 | } | |
110 | ||
111 | /* | |
112 | * This is the real entry point. It passes the initial stack into | |
113 | * the C entry point. | |
114 | */ | |
115 | asm ( | |
116 | ".text\n" | |
117 | ".global _start\n" | |
4ebbefd6 AL |
118 | ".type _start,@function\n" |
119 | "_start:\n\t" | |
120 | #ifdef __x86_64__ | |
121 | "mov %rsp,%rdi\n\t" | |
122 | "jmp c_main" | |
123 | #else | |
124 | "push %esp\n\t" | |
125 | "call c_main\n\t" | |
126 | "int $3" | |
127 | #endif | |
98eedc3a | 128 | ); |