Linux Audio

Check our new training course

Loading...
  1/*
  2 * vdso_test.c: Sample code to test parse_vdso.c on x86_64
  3 * Copyright (c) 2011 Andy Lutomirski
  4 * Subject to the GNU General Public License, version 2
  5 *
  6 * You can amuse yourself by compiling with:
  7 * gcc -std=gnu99 -nostdlib
  8 *     -Os -fno-asynchronous-unwind-tables -flto
  9 *      vdso_test.c parse_vdso.c -o vdso_test
 10 * to generate a small binary with no dependencies at all.
 11 */
 12
 13#include <sys/syscall.h>
 14#include <sys/time.h>
 15#include <unistd.h>
 16#include <stdint.h>
 17
 18extern void *vdso_sym(const char *version, const char *name);
 19extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
 20extern void vdso_init_from_auxv(void *auxv);
 21
 22/* We need a libc functions... */
 23int 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/* ...and two syscalls.  This is x86_64-specific. */
 39static inline long linux_write(int fd, const void *data, size_t len)
 40{
 41
 42	long ret;
 43	asm volatile ("syscall" : "=a" (ret) : "a" (__NR_write),
 44		      "D" (fd), "S" (data), "d" (len) :
 45		      "cc", "memory", "rcx",
 46		      "r8", "r9", "r10", "r11" );
 47	return ret;
 48}
 49
 50static inline void linux_exit(int code)
 51{
 52	asm volatile ("syscall" : : "a" (__NR_exit), "D" (code));
 53}
 54
 55void to_base10(char *lastdig, uint64_t n)
 56{
 57	while (n) {
 58		*lastdig = (n % 10) + '0';
 59		n /= 10;
 60		lastdig--;
 61	}
 62}
 63
 64__attribute__((externally_visible)) void c_main(void **stack)
 65{
 66	/* Parse the stack */
 67	long argc = (long)*stack;
 68	stack += argc + 2;
 69
 70	/* Now we're pointing at the environment.  Skip it. */
 71	while(*stack)
 72		stack++;
 73	stack++;
 74
 75	/* Now we're pointing at auxv.  Initialize the vDSO parser. */
 76	vdso_init_from_auxv((void *)stack);
 77
 78	/* Find gettimeofday. */
 79	typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
 80	gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
 81
 82	if (!gtod)
 83		linux_exit(1);
 84
 85	struct timeval tv;
 86	long ret = gtod(&tv, 0);
 87
 88	if (ret == 0) {
 89		char buf[] = "The time is                     .000000\n";
 90		to_base10(buf + 31, tv.tv_sec);
 91		to_base10(buf + 38, tv.tv_usec);
 92		linux_write(1, buf, sizeof(buf) - 1);
 93	} else {
 94		linux_exit(ret);
 95	}
 96
 97	linux_exit(0);
 98}
 99
100/*
101 * This is the real entry point.  It passes the initial stack into
102 * the C entry point.
103 */
104asm (
105	".text\n"
106	".global _start\n"
107        ".type _start,@function\n"
108        "_start:\n\t"
109        "mov %rsp,%rdi\n\t"
110        "jmp c_main"
111	);