pastebin - collaborative debugging tool
rovema.kpaste.net RSS

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

    
11
22
/*
33
 * linux_vdso_myclockgettime1.c - use Linux VDSO
44
 * shortcut for |clock_gettime()|, even if userland (g)libc
55
 * does not have support for VDSO
66
 *
77
 * Compile with:
88
 * $ clang -std=c99 -g -m32 -Wall -Wextra linux_vdso_myclockgettime1.c \
99
 * 	-lpthread -o linux_vdso_myclockgettime1
1010
 *
1111
 * Written by Roland Mainz <roland.mainz@nrubsig.org>
1212
 *
1313
 */
1414
1515
#define _XOPEN_SOURCE 600
1616
1717
#include <stdio.h>
1818
#include <stddef.h>
1919
#include <stdlib.h>
2020
#include <string.h>
2121
#include <elf.h>
2222
#include <time.h>
2323
#include <pthread.h>
2424
#include <sys/auxv.h>
2525
2626
/* Catch cursed idiots playing around with XPG config */
2727
#if (_XOPEN_SOURCE < 600)
2828
#error _XOPEN_SOURCE wrong version
2929
#endif
3030
3131
/* Build test code ? */
3232
#define MY_CLOCK_GETTIME_TESTS 1
3333
3434
/* debug */
35-
#if 0
35+
#if 1
3636
#define D(x) x
3737
#else
3838
#define D(x)
3939
#endif
4040
4141
4242
/* 32bit vs. 64bit */
4343
#if (__PTRDIFF_WIDTH__ == 32)
4444
typedef Elf32_Ehdr	ElfXX_Ehdr;
4545
typedef Elf32_Shdr	ElfXX_Shdr;
4646
typedef Elf32_Sym	ElfXX_Sym;
4747
#elif (__PTRDIFF_WIDTH__ == 64)
4848
typedef Elf64_Ehdr	ElfXX_Ehdr;
4949
typedef Elf64_Shdr	ElfXX_Shdr;
5050
typedef Elf64_Sym	ElfXX_Sym;
5151
#else
5252
#error Unsupported __PTRDIFF_WIDTH__
5353
#endif
5454
5555
5656
/*
5757
 * get_linux_vdso_sym() - Look up symbol in AUX AT_SYSINFO_EHDR
5858
 */
5959
static
6060
void *get_linux_vdso_sym(const char *funcname)
6161
{
6262
	const char	*dynstr;
6363
	void		*ret = NULL;
6464
	unsigned char	*vdso_addr;
6565
	ssize_t		i;
6666
	size_t		si;
6767
	const char	*name;
6868
	ElfXX_Ehdr	*elf_header;
6969
	ElfXX_Shdr	*section_header;
7070
	ElfXX_Shdr	*s;
7171
	ElfXX_Shdr	*s2;
7272
	ElfXX_Sym	*sym;
7373
7474
	/*
7575
	 * valgrind can disable |AT_SYSINFO_EHDR| - see
7676
	 * https://www.mail-archive.com/kde-bugs-dist@kde.org/msg550927.html
7777
	 */
7878
	vdso_addr = (unsigned char *)getauxval(AT_SYSINFO_EHDR);
7979
	if (!vdso_addr) {
8080
		D((void)fprintf(stderr, "get_linux_vdso_sym: getauxval(AT_SYSINFO_EHDR) failed.\n"));
8181
		return NULL;
8282
	}
8383
8484
	elf_header = (ElfXX_Ehdr *)vdso_addr;
8585
	section_header = (ElfXX_Shdr *)(vdso_addr + elf_header->e_shoff);
8686
8787
	for (dynstr = NULL, i=0L; i < elf_header->e_shnum; i++) {
8888
		s    = &section_header[i];
8989
		s2   = &section_header[elf_header->e_shstrndx];
9090
		name = (const char*)(vdso_addr + s2->sh_offset + s->sh_name);
9191
9292
		if (strcmp(name, ".dynstr") == 0) {
9393
			dynstr = (const char *)(vdso_addr + s->sh_offset);
9494
			break;
9595
		}
9696
	}
9797
9898
	if (!dynstr)
9999
		return NULL;
100100
101101
	for (i=0L; i < elf_header->e_shnum; i++) {
102102
		s    = &section_header[i];
103103
		s2   = &section_header[elf_header->e_shstrndx];
104104
		name = (const char*)(vdso_addr + s2->sh_offset + s->sh_name);
105105
106106
		/* Not .dynsym ? Then look at next section... */
107107
		if (strcmp(name, ".dynsym"))
108108
			continue;
109109
110110
		for (si=0L; si < (s->sh_size/s->sh_entsize); si++) {
111111
			sym = &(((ElfXX_Sym*)(vdso_addr + s->sh_offset))[si]);
112112
			name = dynstr + sym->st_name;
113113
114114
			D((void)fprintf(stderr, "get_linux_vdso_sym: symbol=|%s| vs. |%s|\n",
115115
				funcname, name));
116116
			if (!strcmp(name, funcname)) {
117117
				ret = (void *)(vdso_addr + sym->st_value);
118118
				break;
119119
			}
120120
		}
121121
122122
		if (ret)
123123
			break;
124124
	}
125125
126126
	return ret;
127127
}
128128
129129
130130
/*
131131
 * Initalisation code
132132
 */
133133
typedef int (clock_gettime_func_t)(clockid_t clk_id, struct timespec *tp);
134134
135135
static pthread_once_t my_clock_gettime_func_is_initialized = PTHREAD_ONCE_INIT;
136136
static clock_gettime_func_t *my_clock_gettime_func = NULL;
137137
138138
139139
static
140140
void my_clock_gettime_func_init(void)
141141
{
142142
	my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("clock_gettime");
143143
	if (!my_clock_gettime_func)
144144
		my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("__vdso_clock_gettime");
145145
146146
	D((void)fprintf(stderr, "my_clock_gettime_func_init: "
147147
		"my_clock_gettime_func = 0x%lx (%s)\n",
148148
		(long)my_clock_gettime_func,
149149
		(my_clock_gettime_func?
150150
			"Using fast codepath":
151151
			"Using slow codepath")));
152152
	if (!my_clock_gettime_func) {
153153
		(void)fprintf(stderr, "my_clock_gettime_func_init: "
154154
			"WARNING: aux symbol for clock_gettime not found"
155155
			", using slow libc codepath.\n");
156156
	}
157157
}
158158
159159
160160
/*
161161
 * |my_clock_gettime()| - our "public" interface
162162
 *
163163
 * Notes:
164164
 * - The first call might be slower because the call to
165165
 * |my_clock_gettime_func_init()|
166166
 */
167167
int my_clock_gettime(clockid_t clk_id, struct timespec *tp)
168168
{
169169
	(void)pthread_once(&my_clock_gettime_func_is_initialized,
170170
		my_clock_gettime_func_init);
171171
172172
	if (my_clock_gettime_func) {
173173
		/* our MY_CLOCK_GETTIME_TESTSown "fast" codepath */
174174
		return (*my_clock_gettime_func)(clk_id, tp);
175175
	}
176176
	else
177177
	{
178178
		/* libc codepath, whatever they use - might be VDSO, might be syscall */
179179
		return clock_gettime(clk_id, tp);
180180
	}
181181
}
182182
183183
184184
#ifdef MY_CLOCK_GETTIME_TESTS
185185
/*
186186
 * test code
187187
 */
188188
static
189189
void test_my_clock_gettime1(void)
190190
{
191191
	/*
192192
	 * dummy call to |my_clock_gettime()| to force initalisation
193193
	 * via |my_clock_gettime_func_init()|
194194
	 */
195195
	struct timespec dummy;
196196
	(void)my_clock_gettime(CLOCK_REALTIME, &dummy);
197197
198198
#define PRINT_CLOCK(clock) \
199199
	{ \
200200
		struct timespec tp1, tp2; \
201201
		/* \
202202
		 * print timestamps: \
203203
		 * first libc implementation, then our implementation, \
204204
		 * so that the difference is the call time of our \
205205
		 * codepath. Requires |my_clock_gettime_func_init()| \
206206
		 * to run before this sequence!! \
207207
		 */ \
208208
		(void)clock_gettime((clock), &tp1); \
209209
		(void)my_clock_gettime((clock), &tp2); \
210210
		(void)printf( \
211211
			"%-20s libc_impl = \t(%-10ld\t%-10ld), " \
212212
			"our_impl = \t(%-10ld\t%-10ld)\n", \
213213
			#clock ":", \
214214
			(long)tp1.tv_sec, (long)tp1.tv_nsec, \
215215
			(long)tp2.tv_sec, (long)tp2.tv_nsec); \
216216
	}
217217
218218
	PRINT_CLOCK(CLOCK_REALTIME);
219219
	PRINT_CLOCK(CLOCK_MONOTONIC);
220220
}
221221
222222
223223
int main(int ac, char *av[])
224224
{
225225
	(void)ac;
226226
	(void)av;
227227
228228
	test_my_clock_gettime1();
229229
230230
	return EXIT_SUCCESS;
231231
}
232232
233233
#endif /* MY_CLOCK_GETTIME_TESTS */
234234
235235
236236

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