Skip to content

Commit 8770a91

Browse files
t-8chKAGA-KOKO
authored andcommitted
selftests: vDSO: vdso_standalone_test_x86: Switch to nolibc
vdso_standalone_test_x86 provides its own ASM syscall wrappers and _start() implementation. The in-tree nolibc library already provides this functionality for multiple architectures. By making use of nolibc, the standalone testcase can be built from the exact same codebase as the non-standalone version. Signed-off-by: Thomas Weißschuh <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Vincenzo Frascino <[email protected]> Acked-by: Shuah Khan <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent 4f65df6 commit 8770a91

File tree

2 files changed

+39
-144
lines changed

2 files changed

+39
-144
lines changed

tools/testing/selftests/vDSO/Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ include ../lib.mk
2222

2323
CFLAGS += $(TOOLS_INCLUDES)
2424

25+
CFLAGS_NOLIBC := -nostdlib -nostdinc -ffreestanding -fno-asynchronous-unwind-tables \
26+
-fno-stack-protector -include $(top_srcdir)/tools/include/nolibc/nolibc.h \
27+
-I$(top_srcdir)/tools/include/nolibc/ $(KHDR_INCLUDES)
28+
2529
$(OUTPUT)/vdso_test_gettimeofday: parse_vdso.c vdso_test_gettimeofday.c
2630
$(OUTPUT)/vdso_test_getcpu: parse_vdso.c vdso_test_getcpu.c
2731
$(OUTPUT)/vdso_test_abi: parse_vdso.c vdso_test_abi.c
2832
$(OUTPUT)/vdso_test_clock_getres: vdso_test_clock_getres.c
2933

30-
$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
31-
$(OUTPUT)/vdso_standalone_test_x86: CFLAGS +=-nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector
34+
$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c | headers
35+
$(OUTPUT)/vdso_standalone_test_x86: CFLAGS:=$(CFLAGS_NOLIBC) $(CFLAGS)
3236

3337
$(OUTPUT)/vdso_test_correctness: vdso_test_correctness.c
3438
$(OUTPUT)/vdso_test_correctness: LDFLAGS += -ldl
Lines changed: 33 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,167 +1,58 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/*
3-
* vdso_test.c: Sample code to test parse_vdso.c on x86
4-
* Copyright (c) 2011-2014 Andy Lutomirski
3+
* vdso_test_gettimeofday.c: Sample code to test parse_vdso.c and
4+
* vDSO gettimeofday()
5+
* Copyright (c) 2014 Andy Lutomirski
56
*
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.
7+
* Compile with:
8+
* gcc -std=gnu99 vdso_test_gettimeofday.c parse_vdso_gettimeofday.c
9+
*
10+
* Tested on x86, 32-bit and 64-bit. It may work on other architectures, too.
1211
*/
1312

14-
#include <sys/syscall.h>
13+
#include <stdio.h>
14+
#ifndef NOLIBC
15+
#include <sys/auxv.h>
1516
#include <sys/time.h>
16-
#include <unistd.h>
17-
#include <stdint.h>
18-
#include <linux/auxvec.h>
19-
20-
#include "parse_vdso.h"
21-
22-
/* We need some libc functions... */
23-
int strcmp(const char *a, const char *b)
24-
{
25-
/* This implementation is buggy: it never returns -1. */
26-
while (*a || *b) {
27-
if (*a != *b)
28-
return 1;
29-
if (*a == 0 || *b == 0)
30-
return 1;
31-
a++;
32-
b++;
33-
}
34-
35-
return 0;
36-
}
37-
38-
/*
39-
* The clang build needs this, although gcc does not.
40-
* Stolen from lib/string.c.
41-
*/
42-
void *memcpy(void *dest, const void *src, size_t count)
43-
{
44-
char *tmp = dest;
45-
const char *s = src;
46-
47-
while (count--)
48-
*tmp++ = *s++;
49-
return dest;
50-
}
51-
52-
/* ...and two syscalls. This is x86-specific. */
53-
static inline long x86_syscall3(long nr, long a0, long a1, long a2)
54-
{
55-
long ret;
56-
#ifdef __x86_64__
57-
asm volatile ("syscall" : "=a" (ret) : "a" (nr),
58-
"D" (a0), "S" (a1), "d" (a2) :
59-
"cc", "memory", "rcx",
60-
"r8", "r9", "r10", "r11" );
61-
#else
62-
asm volatile ("int $0x80" : "=a" (ret) : "a" (nr),
63-
"b" (a0), "c" (a1), "d" (a2) :
64-
"cc", "memory" );
6517
#endif
66-
return ret;
67-
}
68-
69-
static inline long linux_write(int fd, const void *data, size_t len)
70-
{
71-
return x86_syscall3(__NR_write, fd, (long)data, (long)len);
72-
}
7318

74-
static inline void linux_exit(int code)
75-
{
76-
x86_syscall3(__NR_exit, code, 0, 0);
77-
}
78-
79-
void to_base10(char *lastdig, time_t n)
80-
{
81-
while (n) {
82-
*lastdig = (n % 10) + '0';
83-
n /= 10;
84-
lastdig--;
85-
}
86-
}
19+
#include "../kselftest.h"
20+
#include "parse_vdso.h"
21+
#include "vdso_config.h"
22+
#include "vdso_call.h"
8723

88-
unsigned long getauxval(const unsigned long *auxv, unsigned long type)
24+
int main(int argc, char **argv)
8925
{
90-
unsigned long ret;
91-
92-
if (!auxv)
93-
return 0;
94-
95-
while (1) {
96-
if (!auxv[0] && !auxv[1]) {
97-
ret = 0;
98-
break;
99-
}
26+
const char *version = versions[VDSO_VERSION];
27+
const char **name = (const char **)&names[VDSO_NAMES];
10028

101-
if (auxv[0] == type) {
102-
ret = auxv[1];
103-
break;
104-
}
105-
106-
auxv += 2;
29+
unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
30+
if (!sysinfo_ehdr) {
31+
printf("AT_SYSINFO_EHDR is not present!\n");
32+
return KSFT_SKIP;
10733
}
10834

109-
return ret;
110-
}
111-
112-
void c_main(void **stack)
113-
{
114-
/* Parse the stack */
115-
long argc = (long)*stack;
116-
stack += argc + 2;
117-
118-
/* Now we're pointing at the environment. Skip it. */
119-
while(*stack)
120-
stack++;
121-
stack++;
122-
123-
/* Now we're pointing at auxv. Initialize the vDSO parser. */
124-
vdso_init_from_sysinfo_ehdr(getauxval((unsigned long *)stack, AT_SYSINFO_EHDR));
35+
vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
12536

12637
/* Find gettimeofday. */
12738
typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
128-
gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
39+
gtod_t gtod = (gtod_t)vdso_sym(version, name[0]);
12940

130-
if (!gtod)
131-
linux_exit(1);
41+
if (!gtod) {
42+
printf("Could not find %s\n", name[0]);
43+
return KSFT_SKIP;
44+
}
13245

13346
struct timeval tv;
134-
long ret = gtod(&tv, 0);
47+
long ret = VDSO_CALL(gtod, 2, &tv, 0);
13548

13649
if (ret == 0) {
137-
char buf[] = "The time is .000000\n";
138-
to_base10(buf + 31, tv.tv_sec);
139-
to_base10(buf + 38, tv.tv_usec);
140-
linux_write(1, buf, sizeof(buf) - 1);
50+
printf("The time is %lld.%06lld\n",
51+
(long long)tv.tv_sec, (long long)tv.tv_usec);
14152
} else {
142-
linux_exit(ret);
53+
printf("%s failed\n", name[0]);
54+
return KSFT_FAIL;
14355
}
14456

145-
linux_exit(0);
57+
return 0;
14658
}
147-
148-
/*
149-
* This is the real entry point. It passes the initial stack into
150-
* the C entry point.
151-
*/
152-
asm (
153-
".text\n"
154-
".global _start\n"
155-
".type _start,@function\n"
156-
"_start:\n\t"
157-
#ifdef __x86_64__
158-
"mov %rsp,%rdi\n\t"
159-
"and $-16,%rsp\n\t"
160-
"sub $8,%rsp\n\t"
161-
"jmp c_main"
162-
#else
163-
"push %esp\n\t"
164-
"call c_main\n\t"
165-
"int $3"
166-
#endif
167-
);

0 commit comments

Comments
 (0)