pastebin - collaborative debugging tool
rovema.kpaste.net RSS

Difference between
modified post 11495b4 by Anonymous on Thu 29th Sep 2022 10:20
original post 0aef2778 by Anonymous on Wed 28th Sep 2022 16:49
Download diff
Show old version | new version | both versions

    
1+
12
/*
23
 * linux_vdso_myclockgettime1.c - use Linux VDSO
34
 * shortcut for |clock_gettime()|, even if userland (g)libc
45
 * does not have support for VDSO
56
 *
67
 * Compile with:
78
 * $ clang -std=c99 -g -m32 -Wall -Wextra linux_vdso_myclockgettime1.c \
89
 * 	-lpthread -o linux_vdso_myclockgettime1
910
 *
1011
 * Written by Roland Mainz <roland.mainz@nrubsig.org>
1112
 *
1213
 */
1314
1415
#define _XOPEN_SOURCE 600
1516
1617
#include <stdio.h>
1718
#include <stddef.h>
1819
#include <stdlib.h>
1920
#include <string.h>
2021
#include <elf.h>
2122
#include <time.h>
2223
#include <pthread.h>
2324
#include <sys/auxv.h>
2425
26+
/* Catch cursed idiots playing around with XPG config */
2527
#if (_XOPEN_SOURCE < 600)
2628
#error _XOPEN_SOURCE wrong version
2729
#endif
2830
29-
#if (__PTRDIFF_WIDTH__ == 32)
31+
/* Build test code ? */
30-
typedef Elf32_Ehdr	ElfXX_Ehdr;
32+
#define MY_CLOCK_GETTIME_TESTS 1
4033
4134
/* debug */
4235
#if 0
4336
#define D(x) x
4437
#else
4538
#define D(x)
4639
#endif
4740
48-
static
41+
49-
void *get_linux_vdso_sym(const char *funcname)
42+
/* 32bit vs. 64bit */
50-
{
43+
#if (__PTRDIFF_WIDTH__ == 32)
51-
	const char	*dynstr = NULL;
44+
typedef Elf32_Ehdr	ElfXX_Ehdr;
52-
	void		*ret = NULL;
45+
typedef Elf32_Shdr	ElfXX_Shdr;
53-
	unsigned char	*vdso_addr;
46+
typedef Elf32_Sym	ElfXX_Sym;
54-
	ssize_t		i;
47+
#elif (__PTRDIFF_WIDTH__ == 64)
55-
	size_t		si;
48+
typedef Elf64_Ehdr	ElfXX_Ehdr;
56-
	const char	*name;
49+
typedef Elf64_Shdr	ElfXX_Shdr;
57-
	ElfXX_Ehdr	*elf_header;
50+
typedef Elf64_Sym	ElfXX_Sym;
58-
	ElfXX_Shdr	*section_header;
51+
#else
59-
	ElfXX_Shdr	*s;
52+
#error Unsupported __PTRDIFF_WIDTH__
60-
	ElfXX_Shdr	*ss_;
53+
#endif
6254
55+
6356
	/*
64-
	 * valgrind can disable |AT_SYSINFO_EHDR| - see
57+
 * get_linux_vdso_sym() - Look up symbol in AUX AT_SYSINFO_EHDR
6658
	 */
67-
	vdso_addr = (unsigned char *)getauxval(AT_SYSINFO_EHDR);
59+
static
68-
	if (!vdso_addr) {
60+
void *get_linux_vdso_sym(const char *funcname)
69-
		D((void)fprintf(stderr, "get_linux_vdso_sym: getauxval(AT_SYSINFO_EHDR) failed.\n"));
61+
{
70-
		return NULL;
62+
	const char	*dynstr;
71-
	}
63+
	void		*ret = NULL;
64+
	unsigned char	*vdso_addr;
7273
73-
	elf_header = (ElfXX_Ehdr *)vdso_addr;
74+
	/*
74-
	section_header = (ElfXX_Shdr *)(vdso_addr + elf_header->e_shoff);
75+
	 * valgrind can disable |AT_SYSINFO_EHDR| - see
76+
	 * https://www.mail-archive.com/kde-bugs-dist@kde.org/msg550927.html
7583
76-
	for (i=0L; i < elf_header->e_shnum; i++) {
84+
	elf_header = (ElfXX_Ehdr *)vdso_addr;
77-
		s = &section_header[i];
85+
	section_header = (ElfXX_Shdr *)(vdso_addr + elf_header->e_shoff);
8086
87+
	for (dynstr = NULL, i=0L; i < elf_header->e_shnum; i++) {
8192
		if (strcmp(name, ".dynstr") == 0) {
8293
			dynstr = (const char *)(vdso_addr + s->sh_offset);
8394
			break;
8495
		}
8596
	}
8697
98+
	if (!dynstr)
87101
	for (i=0L; i < elf_header->e_shnum; i++) {
88-
		s = &section_header[i];
102+
		s    = &section_header[i];
89-
		ss_ = &section_header[elf_header->e_shstrndx];
103+
		s2   = &section_header[elf_header->e_shstrndx];
90-
		name = (const char*)(vdso_addr + ss_->sh_offset + s->sh_name);
104+
		name = (const char*)(vdso_addr + s2->sh_offset + s->sh_name);
91105
92106
		/* Not .dynsym ? Then look at next section... */
93107
		if (strcmp(name, ".dynsym"))
94108
			continue;
95109
96110
		for (si=0L; si < (s->sh_size/s->sh_entsize); si++) {
97111
			sym = &(((ElfXX_Sym*)(vdso_addr + s->sh_offset))[si]);
98112
			name = dynstr + sym->st_name;
99113
100114
			D((void)fprintf(stderr, "get_linux_vdso_sym: symbol=|%s| vs. |%s|\n",
101115
				funcname, name));
102116
			if (!strcmp(name, funcname)) {
103117
				ret = (void *)(vdso_addr + sym->st_value);
104118
				break;
105119
			}
106120
		}
121+
107122
		if (ret)
108123
			break;
109124
	}
110125
111126
	return ret;
112127
}
113128
114-
typedef int (clock_gettime_func_t)(clockid_t clk_id, struct timespec *tp);
115129
130+
/*
116135
static pthread_once_t my_clock_gettime_func_is_initialized = PTHREAD_ONCE_INIT;
117-
clock_gettime_func_t *my_clock_gettime_func = NULL;
136+
static clock_gettime_func_t *my_clock_gettime_func = NULL;
118137
138+
119140
void my_clock_gettime_func_init(void)
120141
{
121142
	my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("clock_gettime");
122143
	if (!my_clock_gettime_func)
123144
		my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("__vdso_clock_gettime");
124145
125146
	D((void)fprintf(stderr, "my_clock_gettime_func_init: "
126147
		"my_clock_gettime_func = 0x%lx (%s)\n",
127148
		(long)my_clock_gettime_func,
128149
		(my_clock_gettime_func?
129150
			"Using fast codepath":
130151
			"Using slow codepath")));
131152
	if (!my_clock_gettime_func) {
132153
		(void)fprintf(stderr, "my_clock_gettime_func_init: "
133154
			"WARNING: aux symbol for clock_gettime not found"
134155
			", using slow libc codepath.\n");
135156
	}
136157
}
137158
138159
139160
/*
140-
 * my_clock_gettime() - our "public" interface
161+
 * |my_clock_gettime()| - our "public" interface
141162
 *
142163
 * Notes:
143164
 * - The first call might be slower because the call to
144165
 * |my_clock_gettime_func_init()|
145166
 */
146167
int my_clock_gettime(clockid_t clk_id, struct timespec *tp)
147168
{
148169
	(void)pthread_once(&my_clock_gettime_func_is_initialized,
149170
		my_clock_gettime_func_init);
150171
151172
	if (my_clock_gettime_func) {
152-
		/* our own "fast" codepath */
173+
		/* our MY_CLOCK_GETTIME_TESTSown "fast" codepath */
153174
		return (*my_clock_gettime_func)(clk_id, tp);
154175
	}
155176
	else
156177
	{
157178
		/* libc codepath, whatever they use - might be VDSO, might be syscall */
158179
		return clock_gettime(clk_id, tp);
159180
	}
160181
}
161182
183+
165185
	/*
186+
 * test code
168187
	 */
188+
static
169195
	struct timespec dummy;
170196
	(void)my_clock_gettime(CLOCK_REALTIME, &dummy);
171197
172198
#define PRINT_CLOCK(clock) \
173199
	{ \
174200
		struct timespec tp1, tp2; \
175201
		/* \
202+
		 * print timestamps: \
176203
		 * first libc implementation, then our implementation, \
177204
		 * so that the difference is the call time of our \
178205
		 * codepath. Requires |my_clock_gettime_func_init()| \
179206
		 * to run before this sequence!! \
180207
		 */ \
181208
		(void)clock_gettime((clock), &tp1); \
182209
		(void)my_clock_gettime((clock), &tp2); \
183210
		(void)printf( \
184211
			"%-20s libc_impl = \t(%-10ld\t%-10ld), " \
185212
			"our_impl = \t(%-10ld\t%-10ld)\n", \
186213
			#clock ":", \
187214
			(long)tp1.tv_sec, (long)tp1.tv_nsec, \
188215
			(long)tp2.tv_sec, (long)tp2.tv_nsec); \
189216
	}
190217
191218
	PRINT_CLOCK(CLOCK_REALTIME);
192219
	PRINT_CLOCK(CLOCK_MONOTONIC);
193220
}
194221
222+
195223
int main(int ac, char *av[])
196224
{
197225
	(void)ac;
198226
	(void)av;
199227
200228
	test_my_clock_gettime1();
201229
202230
	return EXIT_SUCCESS;
203231
}
204232
205-
233+
#endif /* MY_CLOCK_GETTIME_TESTS */
206234
207235
208236

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.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at