All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] vDSO reference parser updates and Go workaround
@ 2014-06-12 18:47 Andy Lutomirski
  2014-06-12 18:47 ` [PATCH 1/3] doc,vdso: Rename vdso_test.c to vdso_standalone_test_x86.c Andy Lutomirski
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Andy Lutomirski @ 2014-06-12 18:47 UTC (permalink / raw)
  To: hpa, Kui Zhang; +Cc: x86, linux-kernel, Andy Lutomirski

Patches 1 and 2 update the vDSO reference parser.

Despite the late submission, this might be 3.16 material: it's just
documentation.  If I'd been more on top of this, I would have done it
for 3.15.  It's also probably worthwhile given that there is at least
one rather buggy vDSO parser in the wild.

Patch 3 makes "Hello world" as built by Go stop segfaulting.  It's
a performance regression for Go programs: it causes them to stop
finding any symbols in the vDSO, but that's a lot better than
segfaulting.  It has big-endian issues, though, and it's ugly,
and it should probably be disabled for x32.

Andy Lutomirski (3):
  doc,vdso: Rename vdso_test.c to vdso_standalone_test_x86.c
  doc,vdso: Make vDSO examples more portable
  x86,vdso: Hack to keep 64-bit Go programs working

 Documentation/vDSO/parse_vdso.c               |  59 ++++++------
 Documentation/vDSO/vdso_standalone_test_x86.c | 128 ++++++++++++++++++++++++++
 Documentation/vDSO/vdso_test.c                | 103 +++++----------------
 arch/x86/vdso/Makefile                        |   2 +-
 arch/x86/vdso/vdso-fakesections.c             |  20 ++++
 arch/x86/vdso/vdso2c.h                        |  21 ++++-
 6 files changed, 219 insertions(+), 114 deletions(-)
 create mode 100644 Documentation/vDSO/vdso_standalone_test_x86.c
 create mode 100644 arch/x86/vdso/vdso-fakesections.c

-- 
1.9.3


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] doc,vdso: Rename vdso_test.c to vdso_standalone_test_x86.c
  2014-06-12 18:47 [PATCH 0/3] vDSO reference parser updates and Go workaround Andy Lutomirski
@ 2014-06-12 18:47 ` Andy Lutomirski
  2014-06-12 18:47 ` [PATCH 2/3] doc,vdso: Make vDSO examples more portable Andy Lutomirski
  2014-06-12 18:47 ` [PATCH 3/3] x86,vdso: Hack to keep 64-bit Go programs working Andy Lutomirski
  2 siblings, 0 replies; 7+ messages in thread
From: Andy Lutomirski @ 2014-06-12 18:47 UTC (permalink / raw)
  To: hpa, Kui Zhang; +Cc: x86, linux-kernel, Andy Lutomirski

This thing is hopelessly x86_64-specific: it's an example of how to
access the vDSO without any runtime support at all.

Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
 Documentation/vDSO/vdso_standalone_test_x86.c | 111 ++++++++++++++++++++++++++
 Documentation/vDSO/vdso_test.c                | 111 --------------------------
 2 files changed, 111 insertions(+), 111 deletions(-)
 create mode 100644 Documentation/vDSO/vdso_standalone_test_x86.c
 delete mode 100644 Documentation/vDSO/vdso_test.c

diff --git a/Documentation/vDSO/vdso_standalone_test_x86.c b/Documentation/vDSO/vdso_standalone_test_x86.c
new file mode 100644
index 0000000..1523f5d
--- /dev/null
+++ b/Documentation/vDSO/vdso_standalone_test_x86.c
@@ -0,0 +1,111 @@
+/*
+ * vdso_test.c: Sample code to test parse_vdso.c on x86_64
+ * Copyright (c) 2011 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
+ *      vdso_standalone_test_x86.c parse_vdso.c
+ * to generate a small binary with no dependencies at all.
+ */
+
+#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_64-specific. */
+static inline long linux_write(int fd, const void *data, size_t len)
+{
+
+	long ret;
+	asm volatile ("syscall" : "=a" (ret) : "a" (__NR_write),
+		      "D" (fd), "S" (data), "d" (len) :
+		      "cc", "memory", "rcx",
+		      "r8", "r9", "r10", "r11" );
+	return ret;
+}
+
+static inline void linux_exit(int code)
+{
+	asm volatile ("syscall" : : "a" (__NR_exit), "D" (code));
+}
+
+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"
+        "mov %rsp,%rdi\n\t"
+        "jmp c_main"
+	);
diff --git a/Documentation/vDSO/vdso_test.c b/Documentation/vDSO/vdso_test.c
deleted file mode 100644
index fff6334..0000000
--- a/Documentation/vDSO/vdso_test.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * vdso_test.c: Sample code to test parse_vdso.c on x86_64
- * Copyright (c) 2011 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
- *      vdso_test.c parse_vdso.c -o vdso_test
- * to generate a small binary with no dependencies at all.
- */
-
-#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_64-specific. */
-static inline long linux_write(int fd, const void *data, size_t len)
-{
-
-	long ret;
-	asm volatile ("syscall" : "=a" (ret) : "a" (__NR_write),
-		      "D" (fd), "S" (data), "d" (len) :
-		      "cc", "memory", "rcx",
-		      "r8", "r9", "r10", "r11" );
-	return ret;
-}
-
-static inline void linux_exit(int code)
-{
-	asm volatile ("syscall" : : "a" (__NR_exit), "D" (code));
-}
-
-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"
-        "mov %rsp,%rdi\n\t"
-        "jmp c_main"
-	);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] doc,vdso: Make vDSO examples more portable
  2014-06-12 18:47 [PATCH 0/3] vDSO reference parser updates and Go workaround Andy Lutomirski
  2014-06-12 18:47 ` [PATCH 1/3] doc,vdso: Rename vdso_test.c to vdso_standalone_test_x86.c Andy Lutomirski
@ 2014-06-12 18:47 ` Andy Lutomirski
  2014-06-12 20:01   ` H. Peter Anvin
  2014-06-12 18:47 ` [PATCH 3/3] x86,vdso: Hack to keep 64-bit Go programs working Andy Lutomirski
  2 siblings, 1 reply; 7+ messages in thread
From: Andy Lutomirski @ 2014-06-12 18:47 UTC (permalink / raw)
  To: hpa, Kui Zhang; +Cc: x86, linux-kernel, Andy Lutomirski, Stefani Seibold

This adds a new vdso_test.c that's written entirely in C.  It also
makes all of the vDSO examples work on 32-bit x86.

Cc: Stefani Seibold <stefani@seibold.net>
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
 Documentation/vDSO/parse_vdso.c               | 59 +++++++++++++++------------
 Documentation/vDSO/vdso_standalone_test_x86.c | 45 +++++++++++++-------
 Documentation/vDSO/vdso_test.c                | 50 +++++++++++++++++++++++
 3 files changed, 113 insertions(+), 41 deletions(-)
 create mode 100644 Documentation/vDSO/vdso_test.c

diff --git a/Documentation/vDSO/parse_vdso.c b/Documentation/vDSO/parse_vdso.c
index 8587020..ca23f06 100644
--- a/Documentation/vDSO/parse_vdso.c
+++ b/Documentation/vDSO/parse_vdso.c
@@ -1,6 +1,6 @@
 /*
  * parse_vdso.c: Linux reference vDSO parser
- * Written by Andrew Lutomirski, 2011.
+ * Written by Andrew Lutomirski, 2011-2014.
  *
  * This code is meant to be linked in to various programs that run on Linux.
  * As such, it is available with as few restrictions as possible.  This file
@@ -11,7 +11,7 @@
  * it starts a program.  It works equally well in statically and dynamically
  * linked binaries.
  *
- * This code is tested on x86_64.  In principle it should work on any 64-bit
+ * This code is tested on x86.  In principle it should work on any
  * architecture that has a vDSO.
  */
 
@@ -20,6 +20,8 @@
 #include <string.h>
 #include <elf.h>
 
+#include <asm/bitsperlong.h>
+
 /*
  * To use this vDSO parser, first call one of the vdso_init_* functions.
  * If you've already parsed auxv, then pass the value of AT_SYSINFO_EHDR
@@ -45,11 +47,14 @@ extern void *vdso_sym(const char *version, const char *name);
 
 
 /* And here's the code. */
-
-#ifndef __x86_64__
-# error Not yet ported to non-x86_64 architectures
+#ifndef __BITS_PER_LONG
+#error We need __BITS_PER_LONG
 #endif
 
+#define ELF_BITS2(bits, x) Elf##bits##_##x
+#define ELF_BITS(bits, x) ELF_BITS2(bits, x)
+#define ELF(x) ELF_BITS(__BITS_PER_LONG, x)
+
 static struct vdso_info
 {
 	bool valid;
@@ -59,14 +64,14 @@ static struct vdso_info
 	uintptr_t load_offset;  /* load_addr - recorded vaddr */
 
 	/* Symbol table */
-	Elf64_Sym *symtab;
+	ELF(Sym) *symtab;
 	const char *symstrings;
-	Elf64_Word *bucket, *chain;
-	Elf64_Word nbucket, nchain;
+	ELF(Word) *bucket, *chain;
+	ELF(Word) nbucket, nchain;
 
 	/* Version table */
-	Elf64_Versym *versym;
-	Elf64_Verdef *verdef;
+	ELF(Versym) *versym;
+	ELF(Verdef) *verdef;
 } vdso_info;
 
 /* Straight from the ELF specification. */
@@ -92,9 +97,9 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
 
 	vdso_info.load_addr = base;
 
-	Elf64_Ehdr *hdr = (Elf64_Ehdr*)base;
-	Elf64_Phdr *pt = (Elf64_Phdr*)(vdso_info.load_addr + hdr->e_phoff);
-	Elf64_Dyn *dyn = 0;
+	ELF(Ehdr) *hdr = (ELF(Ehdr)*)base;
+	ELF(Phdr) *pt = (ELF(Phdr)*)(vdso_info.load_addr + hdr->e_phoff);
+	ELF(Dyn) *dyn = 0;
 
 	/*
 	 * We need two things from the segment table: the load offset
@@ -108,7 +113,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
 				+ (uintptr_t)pt[i].p_offset
 				- (uintptr_t)pt[i].p_vaddr;
 		} else if (pt[i].p_type == PT_DYNAMIC) {
-			dyn = (Elf64_Dyn*)(base + pt[i].p_offset);
+			dyn = (ELF(Dyn)*)(base + pt[i].p_offset);
 		}
 	}
 
@@ -118,7 +123,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
 	/*
 	 * Fish out the useful bits of the dynamic table.
 	 */
-	Elf64_Word *hash = 0;
+	ELF(Word) *hash = 0;
 	vdso_info.symstrings = 0;
 	vdso_info.symtab = 0;
 	vdso_info.versym = 0;
@@ -131,22 +136,22 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
 				 + vdso_info.load_offset);
 			break;
 		case DT_SYMTAB:
-			vdso_info.symtab = (Elf64_Sym *)
+			vdso_info.symtab = (ELF(Sym) *)
 				((uintptr_t)dyn[i].d_un.d_ptr
 				 + vdso_info.load_offset);
 			break;
 		case DT_HASH:
-			hash = (Elf64_Word *)
+			hash = (ELF(Word) *)
 				((uintptr_t)dyn[i].d_un.d_ptr
 				 + vdso_info.load_offset);
 			break;
 		case DT_VERSYM:
-			vdso_info.versym = (Elf64_Versym *)
+			vdso_info.versym = (ELF(Versym) *)
 				((uintptr_t)dyn[i].d_un.d_ptr
 				 + vdso_info.load_offset);
 			break;
 		case DT_VERDEF:
-			vdso_info.verdef = (Elf64_Verdef *)
+			vdso_info.verdef = (ELF(Verdef) *)
 				((uintptr_t)dyn[i].d_un.d_ptr
 				 + vdso_info.load_offset);
 			break;
@@ -168,8 +173,8 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
 	vdso_info.valid = true;
 }
 
-static bool vdso_match_version(Elf64_Versym ver,
-			       const char *name, Elf64_Word hash)
+static bool vdso_match_version(ELF(Versym) ver,
+			       const char *name, ELF(Word) hash)
 {
 	/*
 	 * This is a helper function to check if the version indexed by
@@ -188,7 +193,7 @@ static bool vdso_match_version(Elf64_Versym ver,
 
 	/* First step: find the version definition */
 	ver &= 0x7fff;  /* Apparently bit 15 means "hidden" */
-	Elf64_Verdef *def = vdso_info.verdef;
+	ELF(Verdef) *def = vdso_info.verdef;
 	while(true) {
 		if ((def->vd_flags & VER_FLG_BASE) == 0
 		    && (def->vd_ndx & 0x7fff) == ver)
@@ -197,11 +202,11 @@ static bool vdso_match_version(Elf64_Versym ver,
 		if (def->vd_next == 0)
 			return false;  /* No definition. */
 
-		def = (Elf64_Verdef *)((char *)def + def->vd_next);
+		def = (ELF(Verdef) *)((char *)def + def->vd_next);
 	}
 
 	/* Now figure out whether it matches. */
-	Elf64_Verdaux *aux = (Elf64_Verdaux*)((char *)def + def->vd_aux);
+	ELF(Verdaux) *aux = (ELF(Verdaux)*)((char *)def + def->vd_aux);
 	return def->vd_hash == hash
 		&& !strcmp(name, vdso_info.symstrings + aux->vda_name);
 }
@@ -213,10 +218,10 @@ void *vdso_sym(const char *version, const char *name)
 		return 0;
 
 	ver_hash = elf_hash(version);
-	Elf64_Word chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket];
+	ELF(Word) chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket];
 
 	for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) {
-		Elf64_Sym *sym = &vdso_info.symtab[chain];
+		ELF(Sym) *sym = &vdso_info.symtab[chain];
 
 		/* Check for a defined global or weak function w/ right name. */
 		if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
@@ -243,7 +248,7 @@ void *vdso_sym(const char *version, const char *name)
 
 void vdso_init_from_auxv(void *auxv)
 {
-	Elf64_auxv_t *elf_auxv = auxv;
+	ELF(auxv_t) *elf_auxv = auxv;
 	for (int i = 0; elf_auxv[i].a_type != AT_NULL; i++)
 	{
 		if (elf_auxv[i].a_type == AT_SYSINFO_EHDR) {
diff --git a/Documentation/vDSO/vdso_standalone_test_x86.c b/Documentation/vDSO/vdso_standalone_test_x86.c
index 1523f5d..d462402 100644
--- a/Documentation/vDSO/vdso_standalone_test_x86.c
+++ b/Documentation/vDSO/vdso_standalone_test_x86.c
@@ -1,13 +1,14 @@
 /*
- * vdso_test.c: Sample code to test parse_vdso.c on x86_64
- * Copyright (c) 2011 Andy Lutomirski
+ * 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
+ *     -Os -fno-asynchronous-unwind-tables -flto -lgcc_s
  *      vdso_standalone_test_x86.c parse_vdso.c
- * to generate a small binary with no dependencies at all.
+ * 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>
@@ -35,21 +36,31 @@ int strcmp(const char *a, const char *b)
 	return 0;
 }
 
-/* ...and two syscalls.  This is x86_64-specific. */
-static inline long linux_write(int fd, const void *data, size_t len)
+/* ...and two syscalls.  This is x86-specific. */
+static inline long x86_syscall3(long nr, long a0, long a1, long a2)
 {
-
 	long ret;
-	asm volatile ("syscall" : "=a" (ret) : "a" (__NR_write),
-		      "D" (fd), "S" (data), "d" (len) :
+#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)
 {
-	asm volatile ("syscall" : : "a" (__NR_exit), "D" (code));
+	x86_syscall3(__NR_exit, code, 0, 0);
 }
 
 void to_base10(char *lastdig, uint64_t n)
@@ -104,8 +115,14 @@ __attribute__((externally_visible)) void c_main(void **stack)
 asm (
 	".text\n"
 	".global _start\n"
-        ".type _start,@function\n"
-        "_start:\n\t"
-        "mov %rsp,%rdi\n\t"
-        "jmp c_main"
+	".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
 	);
diff --git a/Documentation/vDSO/vdso_test.c b/Documentation/vDSO/vdso_test.c
new file mode 100644
index 0000000..75b1da2
--- /dev/null
+++ b/Documentation/vDSO/vdso_test.c
@@ -0,0 +1,50 @@
+/*
+ * vdso_test.c: Sample code to test parse_vdso.c
+ * Copyright (c) 2014 Andy Lutomirski
+ * Subject to the GNU General Public License, version 2
+ *
+ * Compile with:
+ * gcc -std=gnu99 vdso_test.c parse_vdso.c
+ *
+ * Tested on x86, 32-bit and 64-bit.  It may work on other architectures, too.
+ */
+
+#include <stdint.h>
+#include <elf.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/time.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);
+
+int main(int argc, char **argv)
+{
+	unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
+	if (!sysinfo_ehdr) {
+		printf("AT_SYSINFO_EHDR is not present!\n");
+		return 0;
+	}
+
+	vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
+
+	/* 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)
+		printf("Could not find __vdso_gettimeofday\n");
+
+	struct timeval tv;
+	long ret = gtod(&tv, 0);
+
+	if (ret == 0) {
+		printf("The time is %lld.%06lld\n",
+		       (long long)tv.tv_sec, (long long)tv.tv_usec);
+	} else {
+		printf("__vdso_gettimeofday failed\n");
+	}
+
+	return 0;
+}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] x86,vdso: Hack to keep 64-bit Go programs working
  2014-06-12 18:47 [PATCH 0/3] vDSO reference parser updates and Go workaround Andy Lutomirski
  2014-06-12 18:47 ` [PATCH 1/3] doc,vdso: Rename vdso_test.c to vdso_standalone_test_x86.c Andy Lutomirski
  2014-06-12 18:47 ` [PATCH 2/3] doc,vdso: Make vDSO examples more portable Andy Lutomirski
@ 2014-06-12 18:47 ` Andy Lutomirski
  2014-06-12 20:21   ` H. Peter Anvin
  2 siblings, 1 reply; 7+ messages in thread
From: Andy Lutomirski @ 2014-06-12 18:47 UTC (permalink / raw)
  To: hpa, Kui Zhang; +Cc: x86, linux-kernel, Andy Lutomirski

The Go runtime has a buggy vDSO parser that currently segfaults.
This writes an empty SHT_DYNSYM entry that causes Go's runtime to
malfunction by thinking that the vDSO is empty rather than
malfunctioning by running off the end and segfaulting.

This is currently broken for big-endian build hosts.  The hack
should also be disabled for x32, but I'm not sure what the right way
to do that is.

Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
 arch/x86/vdso/Makefile            |  2 +-
 arch/x86/vdso/vdso-fakesections.c | 20 ++++++++++++++++++++
 arch/x86/vdso/vdso2c.h            | 21 +++++++++++++++++----
 3 files changed, 38 insertions(+), 5 deletions(-)
 create mode 100644 arch/x86/vdso/vdso-fakesections.c

diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 9769df0..ffdeb5b 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -15,7 +15,7 @@ vdso-install-$(VDSO32-y)	+= $(vdso32-images)
 
 
 # files to link into the vdso
-vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
+vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vdso-fakesections.o
 
 vobjs-$(VDSOX32-y) += $(vobjx32s-compat)
 
diff --git a/arch/x86/vdso/vdso-fakesections.c b/arch/x86/vdso/vdso-fakesections.c
new file mode 100644
index 0000000..ef75ece
--- /dev/null
+++ b/arch/x86/vdso/vdso-fakesections.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 Andy Lutomirski
+ * Subject to the GNU Public License, v.2
+ *
+ * Hack to keep broken Go programs working.
+ */
+
+#if __x86_64__  /* hack only needed for the 64-bit vDSO */
+
+#include <linux/elf.h>
+
+extern const __visible struct elf64_shdr vdso_fake_sections[];
+const __visible struct elf64_shdr vdso_fake_sections[] = {
+	{
+		.sh_type = SHT_DYNSYM,
+		.sh_entsize = sizeof(Elf64_Sym),
+	}
+};
+
+#endif
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
index d9f6f61..43d9ab1 100644
--- a/arch/x86/vdso/vdso2c.h
+++ b/arch/x86/vdso/vdso2c.h
@@ -18,6 +18,8 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
 	const char *secstrings;
 	uint64_t syms[NSYMS] = {};
 
+	uint64_t fake_sections_value = 0, fake_sections_size = 0;
+
 	Elf_Phdr *pt = (Elf_Phdr *)(addr + GET_LE(&hdr->e_phoff));
 
 	/* Walk the segment table. */
@@ -84,6 +86,7 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
 			GET_LE(&symtab_hdr->sh_entsize) * i;
 		const char *name = addr + GET_LE(&strtab_hdr->sh_offset) +
 			GET_LE(&sym->st_name);
+
 		for (k = 0; k < NSYMS; k++) {
 			if (!strcmp(name, required_syms[k])) {
 				if (syms[k]) {
@@ -93,6 +96,13 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
 				syms[k] = GET_LE(&sym->st_value);
 			}
 		}
+
+		if (!strcmp(name, "vdso_fake_sections")) {
+			if (fake_sections_value)
+				fail("duplicate vdso_fake_sections\n");
+			fake_sections_value = GET_LE(&sym->st_value);
+			fake_sections_size = GET_LE(&sym->st_size);
+		}
 	}
 
 	/* Validate mapping addresses. */
@@ -112,10 +122,13 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
 	if (syms[sym_end_mapping] % 4096)
 		fail("end_mapping must be a multiple of 4096\n");
 
-	/* Remove sections. */
-	hdr->e_shoff = 0;
-	hdr->e_shentsize = 0;
-	hdr->e_shnum = 0;
+	/* Remove sections or use fakes */
+	if (fake_sections_size % sizeof(Elf_Shdr))
+		fail("vdso_fake_sections size is not a multiple of %ld\n",
+		     (long)sizeof(Elf_Shdr));
+	hdr->e_shoff = fake_sections_value;
+	hdr->e_shentsize = fake_sections_value ? sizeof(Elf_Shdr) : 0;
+	hdr->e_shnum = fake_sections_size / sizeof(Elf_Shdr);
 	hdr->e_shstrndx = SHN_UNDEF; /* SHN_UNDEF == 0 */
 
 	if (!name) {
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] doc,vdso: Make vDSO examples more portable
  2014-06-12 18:47 ` [PATCH 2/3] doc,vdso: Make vDSO examples more portable Andy Lutomirski
@ 2014-06-12 20:01   ` H. Peter Anvin
  0 siblings, 0 replies; 7+ messages in thread
From: H. Peter Anvin @ 2014-06-12 20:01 UTC (permalink / raw)
  To: Andy Lutomirski, Kui Zhang; +Cc: x86, linux-kernel, Stefani Seibold

On 06/12/2014 11:47 AM, Andy Lutomirski wrote:
>  
> +#include <asm/bitsperlong.h>
> +

This isn't portable in any way.  This is probably not the right way to
do this.

The portable way to do this would be something like:

#include <limits.h>

#if ULONG_MAX > 0xffffffffUL
# define ELF_BITS 64
#else
# define ELF_BITS 32
#endif

There is also the option of looking for either __LP64__ or __ILP32__
which isn't 100% portable but works with all newer versions of gcc:

#ifndef ELF_BITS
# ifdef __LP64__
#  define ELF_BITS 64
# elif defined(__ILP32__)
#  define ELF_BITS 32
# else
#  error "Unknown size, please define ELF_BITS"
# endif
#endif

... or something like that.

	-hpa


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3] x86,vdso: Hack to keep 64-bit Go programs working
  2014-06-12 18:47 ` [PATCH 3/3] x86,vdso: Hack to keep 64-bit Go programs working Andy Lutomirski
@ 2014-06-12 20:21   ` H. Peter Anvin
  2014-06-13  1:09     ` Andy Lutomirski
  0 siblings, 1 reply; 7+ messages in thread
From: H. Peter Anvin @ 2014-06-12 20:21 UTC (permalink / raw)
  To: Andy Lutomirski, Kui Zhang; +Cc: x86, linux-kernel

On 06/12/2014 11:47 AM, Andy Lutomirski wrote:
> 
> This is currently broken for big-endian build hosts.  The hack
> should also be disabled for x32, but I'm not sure what the right way
> to do that is.
> 

Well, if it isn't exported into the x32 vdso it isn't an issue, right?

	-hpa


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3] x86,vdso: Hack to keep 64-bit Go programs working
  2014-06-12 20:21   ` H. Peter Anvin
@ 2014-06-13  1:09     ` Andy Lutomirski
  0 siblings, 0 replies; 7+ messages in thread
From: Andy Lutomirski @ 2014-06-13  1:09 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Kui Zhang, X86 ML, linux-kernel

On Thu, Jun 12, 2014 at 1:21 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 06/12/2014 11:47 AM, Andy Lutomirski wrote:
>>
>> This is currently broken for big-endian build hosts.  The hack
>> should also be disabled for x32, but I'm not sure what the right way
>> to do that is.
>>
>
> Well, if it isn't exported into the x32 vdso it isn't an issue, right?

It was, and it broke the build.  v3 fixes it, at the cost of yet more
makefile churn.

>
>         -hpa
>



-- 
Andy Lutomirski
AMA Capital Management, LLC

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-06-13  1:09 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-12 18:47 [PATCH 0/3] vDSO reference parser updates and Go workaround Andy Lutomirski
2014-06-12 18:47 ` [PATCH 1/3] doc,vdso: Rename vdso_test.c to vdso_standalone_test_x86.c Andy Lutomirski
2014-06-12 18:47 ` [PATCH 2/3] doc,vdso: Make vDSO examples more portable Andy Lutomirski
2014-06-12 20:01   ` H. Peter Anvin
2014-06-12 18:47 ` [PATCH 3/3] x86,vdso: Hack to keep 64-bit Go programs working Andy Lutomirski
2014-06-12 20:21   ` H. Peter Anvin
2014-06-13  1:09     ` Andy Lutomirski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.