Difference between
modified post 1a678b by Anonymous on Wed 5th Oct 2022 09:51
original post 11495b4 by Anonymous on Thu 29th Sep 2022 10:20
Download diff
Show
old version |
new version |
both versions
| 1 | 1 | ||
| 2 | 2 | /* | |
| 3 | 3 | * linux_vdso_myclockgettime1.c - use Linux VDSO | |
| 4 | 4 | * shortcut for |clock_gettime()|, even if userland (g)libc | |
| 5 | 5 | * does not have support for VDSO | |
| 6 | 6 | * | |
| 7 | 7 | * Compile with: | |
| 8 | 8 | * $ clang -std=c99 -g -m32 -Wall -Wextra linux_vdso_myclockgettime1.c \ | |
| 9 | 9 | * -lpthread -o linux_vdso_myclockgettime1 | |
| 10 | 10 | * | |
| 11 | 11 | * Written by Roland Mainz <roland.mainz@nrubsig.org> | |
| 12 | 12 | * | |
| 13 | 13 | */ | |
| 14 | 14 | ||
| 15 | 15 | #define _XOPEN_SOURCE 600 | |
| 16 | 16 | ||
| 17 | 17 | #include <stdio.h> | |
| 18 | 18 | #include <stddef.h> | |
| 19 | 19 | #include <stdlib.h> | |
| 20 | 20 | #include <string.h> | |
| 21 | 21 | #include <elf.h> | |
| 22 | 22 | #include <time.h> | |
| 23 | 23 | #include <pthread.h> | |
| 24 | 24 | #include <sys/auxv.h> | |
| 25 | 25 | ||
| 26 | 26 | /* Catch cursed idiots playing around with XPG config */ | |
| 27 | 27 | #if (_XOPEN_SOURCE < 600) | |
| 28 | 28 | #error _XOPEN_SOURCE wrong version | |
| 29 | 29 | #endif | |
| 30 | 30 | ||
| 31 | 31 | /* Build test code ? */ | |
| 32 | 32 | #define MY_CLOCK_GETTIME_TESTS 1 | |
| 33 | 33 | ||
| 34 | 34 | /* debug */ | |
| 35 | - | #if 0 | |
| 35 | + | #if 1 | |
| 36 | 36 | #define D(x) x | |
| 37 | 37 | #else | |
| 38 | 38 | #define D(x) | |
| 39 | 39 | #endif | |
| 40 | 40 | ||
| 41 | 41 | ||
| 42 | 42 | /* 32bit vs. 64bit */ | |
| 43 | 43 | #if (__PTRDIFF_WIDTH__ == 32) | |
| 44 | 44 | typedef Elf32_Ehdr ElfXX_Ehdr; | |
| 45 | 45 | typedef Elf32_Shdr ElfXX_Shdr; | |
| 46 | 46 | typedef Elf32_Sym ElfXX_Sym; | |
| 47 | 47 | #elif (__PTRDIFF_WIDTH__ == 64) | |
| 48 | 48 | typedef Elf64_Ehdr ElfXX_Ehdr; | |
| 49 | 49 | typedef Elf64_Shdr ElfXX_Shdr; | |
| 50 | 50 | typedef Elf64_Sym ElfXX_Sym; | |
| 51 | 51 | #else | |
| 52 | 52 | #error Unsupported __PTRDIFF_WIDTH__ | |
| 53 | 53 | #endif | |
| 54 | 54 | ||
| 55 | 55 | ||
| 56 | 56 | /* | |
| 57 | 57 | * get_linux_vdso_sym() - Look up symbol in AUX AT_SYSINFO_EHDR | |
| 58 | 58 | */ | |
| 59 | 59 | static | |
| 60 | 60 | void *get_linux_vdso_sym(const char *funcname) | |
| 61 | 61 | { | |
| 62 | 62 | const char *dynstr; | |
| 63 | 63 | void *ret = NULL; | |
| 64 | 64 | unsigned char *vdso_addr; | |
| 65 | 65 | ssize_t i; | |
| 66 | 66 | size_t si; | |
| 67 | 67 | const char *name; | |
| 68 | 68 | ElfXX_Ehdr *elf_header; | |
| 69 | 69 | ElfXX_Shdr *section_header; | |
| 70 | 70 | ElfXX_Shdr *s; | |
| 71 | 71 | ElfXX_Shdr *s2; | |
| 72 | 72 | ElfXX_Sym *sym; | |
| 73 | 73 | ||
| 74 | 74 | /* | |
| 75 | 75 | * valgrind can disable |AT_SYSINFO_EHDR| - see | |
| 76 | 76 | * https://www.mail-archive.com/kde-bugs-dist@kde.org/msg550927.html | |
| 77 | 77 | */ | |
| 78 | 78 | vdso_addr = (unsigned char *)getauxval(AT_SYSINFO_EHDR); | |
| 79 | 79 | if (!vdso_addr) { | |
| 80 | 80 | D((void)fprintf(stderr, "get_linux_vdso_sym: getauxval(AT_SYSINFO_EHDR) failed.\n")); | |
| 81 | 81 | return NULL; | |
| 82 | 82 | } | |
| 83 | 83 | ||
| 84 | 84 | elf_header = (ElfXX_Ehdr *)vdso_addr; | |
| 85 | 85 | section_header = (ElfXX_Shdr *)(vdso_addr + elf_header->e_shoff); | |
| 86 | 86 | ||
| 87 | 87 | for (dynstr = NULL, i=0L; i < elf_header->e_shnum; i++) { | |
| 88 | 88 | s = §ion_header[i]; | |
| 89 | 89 | s2 = §ion_header[elf_header->e_shstrndx]; | |
| 90 | 90 | name = (const char*)(vdso_addr + s2->sh_offset + s->sh_name); | |
| 91 | 91 | ||
| 92 | 92 | if (strcmp(name, ".dynstr") == 0) { | |
| 93 | 93 | dynstr = (const char *)(vdso_addr + s->sh_offset); | |
| 94 | 94 | break; | |
| 95 | 95 | } | |
| 96 | 96 | } | |
| 97 | 97 | ||
| 98 | 98 | if (!dynstr) | |
| 99 | 99 | return NULL; | |
| 100 | 100 | ||
| 101 | 101 | for (i=0L; i < elf_header->e_shnum; i++) { | |
| 102 | 102 | s = §ion_header[i]; | |
| 103 | 103 | s2 = §ion_header[elf_header->e_shstrndx]; | |
| 104 | 104 | name = (const char*)(vdso_addr + s2->sh_offset + s->sh_name); | |
| 105 | 105 | ||
| 106 | 106 | /* Not .dynsym ? Then look at next section... */ | |
| 107 | 107 | if (strcmp(name, ".dynsym")) | |
| 108 | 108 | continue; | |
| 109 | 109 | ||
| 110 | 110 | for (si=0L; si < (s->sh_size/s->sh_entsize); si++) { | |
| 111 | 111 | sym = &(((ElfXX_Sym*)(vdso_addr + s->sh_offset))[si]); | |
| 112 | 112 | name = dynstr + sym->st_name; | |
| 113 | 113 | ||
| 114 | 114 | D((void)fprintf(stderr, "get_linux_vdso_sym: symbol=|%s| vs. |%s|\n", | |
| 115 | 115 | funcname, name)); | |
| 116 | 116 | if (!strcmp(name, funcname)) { | |
| 117 | 117 | ret = (void *)(vdso_addr + sym->st_value); | |
| 118 | 118 | break; | |
| 119 | 119 | } | |
| 120 | 120 | } | |
| 121 | 121 | ||
| 122 | 122 | if (ret) | |
| 123 | 123 | break; | |
| 124 | 124 | } | |
| 125 | 125 | ||
| 126 | 126 | return ret; | |
| 127 | 127 | } | |
| 128 | 128 | ||
| 129 | 129 | ||
| 130 | 130 | /* | |
| 131 | 131 | * Initalisation code | |
| 132 | 132 | */ | |
| 133 | 133 | typedef int (clock_gettime_func_t)(clockid_t clk_id, struct timespec *tp); | |
| 134 | 134 | ||
| 135 | 135 | static pthread_once_t my_clock_gettime_func_is_initialized = PTHREAD_ONCE_INIT; | |
| 136 | 136 | static clock_gettime_func_t *my_clock_gettime_func = NULL; | |
| 137 | 137 | ||
| 138 | 138 | ||
| 139 | 139 | static | |
| 140 | 140 | void my_clock_gettime_func_init(void) | |
| 141 | 141 | { | |
| 142 | 142 | my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("clock_gettime"); | |
| 143 | 143 | if (!my_clock_gettime_func) | |
| 144 | 144 | my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("__vdso_clock_gettime"); | |
| 145 | 145 | ||
| 146 | 146 | D((void)fprintf(stderr, "my_clock_gettime_func_init: " | |
| 147 | 147 | "my_clock_gettime_func = 0x%lx (%s)\n", | |
| 148 | 148 | (long)my_clock_gettime_func, | |
| 149 | 149 | (my_clock_gettime_func? | |
| 150 | 150 | "Using fast codepath": | |
| 151 | 151 | "Using slow codepath"))); | |
| 152 | 152 | if (!my_clock_gettime_func) { | |
| 153 | 153 | (void)fprintf(stderr, "my_clock_gettime_func_init: " | |
| 154 | 154 | "WARNING: aux symbol for clock_gettime not found" | |
| 155 | 155 | ", using slow libc codepath.\n"); | |
| 156 | 156 | } | |
| 157 | 157 | } | |
| 158 | 158 | ||
| 159 | 159 | ||
| 160 | 160 | /* | |
| 161 | 161 | * |my_clock_gettime()| - our "public" interface | |
| 162 | 162 | * | |
| 163 | 163 | * Notes: | |
| 164 | 164 | * - The first call might be slower because the call to | |
| 165 | 165 | * |my_clock_gettime_func_init()| | |
| 166 | 166 | */ | |
| 167 | 167 | int my_clock_gettime(clockid_t clk_id, struct timespec *tp) | |
| 168 | 168 | { | |
| 169 | 169 | (void)pthread_once(&my_clock_gettime_func_is_initialized, | |
| 170 | 170 | my_clock_gettime_func_init); | |
| 171 | 171 | ||
| 172 | 172 | if (my_clock_gettime_func) { | |
| 173 | 173 | /* our MY_CLOCK_GETTIME_TESTSown "fast" codepath */ | |
| 174 | 174 | return (*my_clock_gettime_func)(clk_id, tp); | |
| 175 | 175 | } | |
| 176 | 176 | else | |
| 177 | 177 | { | |
| 178 | 178 | /* libc codepath, whatever they use - might be VDSO, might be syscall */ | |
| 179 | 179 | return clock_gettime(clk_id, tp); | |
| 180 | 180 | } | |
| 181 | 181 | } | |
| 182 | 182 | ||
| 183 | 183 | ||
| 184 | 184 | #ifdef MY_CLOCK_GETTIME_TESTS | |
| 185 | 185 | /* | |
| 186 | 186 | * test code | |
| 187 | 187 | */ | |
| 188 | 188 | static | |
| 189 | 189 | void test_my_clock_gettime1(void) | |
| 190 | 190 | { | |
| 191 | 191 | /* | |
| 192 | 192 | * dummy call to |my_clock_gettime()| to force initalisation | |
| 193 | 193 | * via |my_clock_gettime_func_init()| | |
| 194 | 194 | */ | |
| 195 | 195 | struct timespec dummy; | |
| 196 | 196 | (void)my_clock_gettime(CLOCK_REALTIME, &dummy); | |
| 197 | 197 | ||
| 198 | 198 | #define PRINT_CLOCK(clock) \ | |
| 199 | 199 | { \ | |
| 200 | 200 | struct timespec tp1, tp2; \ | |
| 201 | 201 | /* \ | |
| 202 | 202 | * print timestamps: \ | |
| 203 | 203 | * first libc implementation, then our implementation, \ | |
| 204 | 204 | * so that the difference is the call time of our \ | |
| 205 | 205 | * codepath. Requires |my_clock_gettime_func_init()| \ | |
| 206 | 206 | * to run before this sequence!! \ | |
| 207 | 207 | */ \ | |
| 208 | 208 | (void)clock_gettime((clock), &tp1); \ | |
| 209 | 209 | (void)my_clock_gettime((clock), &tp2); \ | |
| 210 | 210 | (void)printf( \ | |
| 211 | 211 | "%-20s libc_impl = \t(%-10ld\t%-10ld), " \ | |
| 212 | 212 | "our_impl = \t(%-10ld\t%-10ld)\n", \ | |
| 213 | 213 | #clock ":", \ | |
| 214 | 214 | (long)tp1.tv_sec, (long)tp1.tv_nsec, \ | |
| 215 | 215 | (long)tp2.tv_sec, (long)tp2.tv_nsec); \ | |
| 216 | 216 | } | |
| 217 | 217 | ||
| 218 | 218 | PRINT_CLOCK(CLOCK_REALTIME); | |
| 219 | 219 | PRINT_CLOCK(CLOCK_MONOTONIC); | |
| 220 | 220 | } | |
| 221 | 221 | ||
| 222 | 222 | ||
| 223 | 223 | int main(int ac, char *av[]) | |
| 224 | 224 | { | |
| 225 | 225 | (void)ac; | |
| 226 | 226 | (void)av; | |
| 227 | 227 | ||
| 228 | 228 | test_my_clock_gettime1(); | |
| 229 | 229 | ||
| 230 | 230 | return EXIT_SUCCESS; | |
| 231 | 231 | } | |
| 232 | 232 | ||
| 233 | 233 | #endif /* MY_CLOCK_GETTIME_TESTS */ | |
| 234 | 234 | ||
| 235 | 235 | ||
| 236 | 236 |
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.
rovema.kpaste.net RSS