forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/lin…
…ux/kernel/git/tip/tip Pull x86 vdso fixes from Peter Anvin: "Fixes for x86/vdso. One is a simple build fix for bigendian hosts, one is to make "make vdso_install" work again, and the rest is about working around a bug in Google's Go language -- two are documentation patches that improves the sample code that the Go coders took, modified, and broke; the other two implements a workaround that keeps existing Go binaries from segfaulting at least" * 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/vdso: Fix vdso_install x86/vdso: Hack to keep 64-bit Go programs working x86/vdso: Add PUT_LE to store little-endian values x86/vdso/doc: Make vDSO examples more portable x86/vdso/doc: Rename vdso_test.c to vdso_standalone_test_x86.c x86, vdso: Remove one final use of htole16()
- Loading branch information
Showing
7 changed files
with
279 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* vdso_test.c: Sample code to test parse_vdso.c on x86 | ||
* Copyright (c) 2011-2014 Andy Lutomirski | ||
* Subject to the GNU General Public License, version 2 | ||
* | ||
* You can amuse yourself by compiling with: | ||
* gcc -std=gnu99 -nostdlib | ||
* -Os -fno-asynchronous-unwind-tables -flto -lgcc_s | ||
* vdso_standalone_test_x86.c parse_vdso.c | ||
* to generate a small binary. On x86_64, you can omit -lgcc_s | ||
* if you want the binary to be completely standalone. | ||
*/ | ||
|
||
#include <sys/syscall.h> | ||
#include <sys/time.h> | ||
#include <unistd.h> | ||
#include <stdint.h> | ||
|
||
extern void *vdso_sym(const char *version, const char *name); | ||
extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); | ||
extern void vdso_init_from_auxv(void *auxv); | ||
|
||
/* We need a libc functions... */ | ||
int strcmp(const char *a, const char *b) | ||
{ | ||
/* This implementation is buggy: it never returns -1. */ | ||
while (*a || *b) { | ||
if (*a != *b) | ||
return 1; | ||
if (*a == 0 || *b == 0) | ||
return 1; | ||
a++; | ||
b++; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
/* ...and two syscalls. This is x86-specific. */ | ||
static inline long x86_syscall3(long nr, long a0, long a1, long a2) | ||
{ | ||
long ret; | ||
#ifdef __x86_64__ | ||
asm volatile ("syscall" : "=a" (ret) : "a" (nr), | ||
"D" (a0), "S" (a1), "d" (a2) : | ||
"cc", "memory", "rcx", | ||
"r8", "r9", "r10", "r11" ); | ||
#else | ||
asm volatile ("int $0x80" : "=a" (ret) : "a" (nr), | ||
"b" (a0), "c" (a1), "d" (a2) : | ||
"cc", "memory" ); | ||
#endif | ||
return ret; | ||
} | ||
|
||
static inline long linux_write(int fd, const void *data, size_t len) | ||
{ | ||
return x86_syscall3(__NR_write, fd, (long)data, (long)len); | ||
} | ||
|
||
static inline void linux_exit(int code) | ||
{ | ||
x86_syscall3(__NR_exit, code, 0, 0); | ||
} | ||
|
||
void to_base10(char *lastdig, uint64_t n) | ||
{ | ||
while (n) { | ||
*lastdig = (n % 10) + '0'; | ||
n /= 10; | ||
lastdig--; | ||
} | ||
} | ||
|
||
__attribute__((externally_visible)) void c_main(void **stack) | ||
{ | ||
/* Parse the stack */ | ||
long argc = (long)*stack; | ||
stack += argc + 2; | ||
|
||
/* Now we're pointing at the environment. Skip it. */ | ||
while(*stack) | ||
stack++; | ||
stack++; | ||
|
||
/* Now we're pointing at auxv. Initialize the vDSO parser. */ | ||
vdso_init_from_auxv((void *)stack); | ||
|
||
/* Find gettimeofday. */ | ||
typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); | ||
gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); | ||
|
||
if (!gtod) | ||
linux_exit(1); | ||
|
||
struct timeval tv; | ||
long ret = gtod(&tv, 0); | ||
|
||
if (ret == 0) { | ||
char buf[] = "The time is .000000\n"; | ||
to_base10(buf + 31, tv.tv_sec); | ||
to_base10(buf + 38, tv.tv_usec); | ||
linux_write(1, buf, sizeof(buf) - 1); | ||
} else { | ||
linux_exit(ret); | ||
} | ||
|
||
linux_exit(0); | ||
} | ||
|
||
/* | ||
* This is the real entry point. It passes the initial stack into | ||
* the C entry point. | ||
*/ | ||
asm ( | ||
".text\n" | ||
".global _start\n" | ||
".type _start,@function\n" | ||
"_start:\n\t" | ||
#ifdef __x86_64__ | ||
"mov %rsp,%rdi\n\t" | ||
"jmp c_main" | ||
#else | ||
"push %esp\n\t" | ||
"call c_main\n\t" | ||
"int $3" | ||
#endif | ||
); |
Oops, something went wrong.