Переглянути джерело

[LibOS] Add support for vDSO

This commit adds vDSO support: creates vDSO memory region which contains
necessary symbols __vdso_{gettimeofday, clock_getime, time, getcpu} with
wrappers to call function pointers with actual LibOS implementation.
On startup, function pointers are setup to point to actual functions.

With this commit, the Glibc modification to not use vDSO can be removed.
Isaku Yamahata 5 роки тому
батько
коміт
0809e5a5e1

+ 1 - 1
LibOS/shim/include/shim_defs.h

@@ -35,7 +35,7 @@
 #define MIGRATE_SYSV_MSG            1
 
 /* ELF aux vectors  */
-#define REQUIRED_ELF_AUXV           7   /* number of LibOS-supported vectors */
+#define REQUIRED_ELF_AUXV           8   /* number of LibOS-supported vectors */
 #define REQUIRED_ELF_AUXV_SPACE     16  /* extra memory space (in bytes) */
 
 #endif /* _SHIM_DEFS_H_ */

+ 31 - 0
LibOS/shim/include/shim_vdso.h

@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 Intel Corporation.
+ * Copyright 2018 Isaku Yamahata <isaku.yamahata at intel.com>
+ *                               <isaku.yamahata at gmail.com>
+ * All Rights Reserved.
+ *
+ * This file is part of Graphene Library OS.
+ *
+ * Graphene Library OS is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Graphene Library OS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SHIM_VDSO_H_
+#define _SHIM_VDSO_H_
+
+extern const uint8_t vdso_so[];
+extern const size_t vdso_so_size;
+
+int vdso_map_migrate(void);
+
+#endif /* _SHIM_VDSO_H_ */

+ 19 - 1
LibOS/shim/src/Makefile

@@ -49,7 +49,9 @@ objs	= $(addprefix bookkeep/shim_,handle vma thread signal) \
 	  elf/shim_rtld \
 	  $(addprefix shim_,init table syscalls checkpoint malloc \
 	  async parser debug object) syscallas start \
-	  $(patsubst %.c,%,$(wildcard sys/*.c))
+	  $(patsubst %.c,%,$(wildcard sys/*.c)) \
+	  vdso/vdso-data
+
 graphene_lib = .lib/graphene-lib.a
 pal_lib = $(RUNTIME_DIR)/libpal-$(PAL_HOST).so
 headers = ../include/*.h ../../../Pal/lib/*.h ../../../Pal/include/pal/*.h
@@ -120,5 +122,21 @@ syscallas.S shim_checkpoint.c: asm-offsets.h
 
 include ../../../Makefile.rules
 
+LDFLAGS-vdso/vdso.so.dbg = -nostdlib -shared \
+	--hash-style=both --build-id -Bsymbolic \
+	-m elf_x86_64 --no-undefined \
+	-z max-page-size=4096 -z common-page-size=4096 \
+	-T vdso/vdso.lds -soname linux-vdso.so.1
+vdso/vdso.so.dbg: LDFLAGS =
+vdso/vdso.so.dbg: vdso/vdso.lds vdso/vdso.o vdso/vdso-note.o
+	$(call cmd,ld)
+
+OBJCOPYFLAGS-vdso/vdso.so = -S
+vdso/vdso.so: vdso/vdso.so.dbg
+	$(call cmd,objcopy)
+
+vdso/vdso-data.o: vdso/vdso.so
+CLEAN_FILES += vdso/vdso.so.dbg vdso/vdso.so
+
 clean:
 	rm -rf $(addsuffix .o,$(objs)) $(shim_target) $(files_to_build) .lib $(CLEAN_FILES)

+ 146 - 19
LibOS/shim/src/elf/shim_rtld.c

@@ -32,6 +32,7 @@
 #include <shim_vma.h>
 #include <shim_checkpoint.h>
 #include <shim_profile.h>
+#include <shim_vdso.h>
 
 #include <errno.h>
 
@@ -55,6 +56,7 @@ enum object_type {
     OBJECT_MAPPED       = 2,
     OBJECT_REMAP        = 3,
     OBJECT_USER         = 4,
+    OBJECT_VDSO         = 5,
 };
 
 /* Structure describing a loaded shared object.  The `l_next' and `l_prev'
@@ -147,6 +149,7 @@ struct link_map * lookup_symbol (const char * undef_name, ElfW(Sym) ** ref);
 
 static struct link_map * loaded_libraries = NULL;
 static struct link_map * internal_map = NULL, * interp_map = NULL;
+static struct link_map * vdso_map = NULL;
 
 /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code.  */
 static ElfW(Addr) resolve_map (const char ** strtab, ElfW(Sym) ** ref)
@@ -376,7 +379,7 @@ __map_elf_object (struct shim_handle * file,
     const char * errstring __attribute__((unused)) = NULL;
     int ret;
 
-    if (type != OBJECT_INTERNAL && !file) {
+    if (type != OBJECT_INTERNAL && type != OBJECT_VDSO && !file) {
         errstring = "shared object has to be backed by file";
         goto call_lose;
     }
@@ -589,9 +592,9 @@ do_remap:
             }
 
 #if BOOKKEEP_INTERNAL_OBJ == 0
-                if (type != OBJECT_INTERNAL && type != OBJECT_USER)
+                if (type != OBJECT_INTERNAL && type != OBJECT_USER && type != OBJECT_VDSO)
 #else
-                if (type != OBJECT_USER)
+                if (type != OBJECT_USER && type != OBJECT_VDSO)
 #endif
                     bkeep_mmap(mapaddr, c->mapend - c->mapstart, c->prot,
                                c->flags|MAP_FIXED|MAP_PRIVATE|
@@ -623,7 +626,9 @@ postmap:
 
             if (type != OBJECT_MAPPED &&
                 type != OBJECT_INTERNAL &&
-                type != OBJECT_USER && zeropage > zero) {
+                type != OBJECT_USER &&
+                type != OBJECT_VDSO &&
+                zeropage > zero) {
                 /* Zero the final part of the last page of the segment.  */
                 if (__builtin_expect ((c->prot & PROT_WRITE) == 0, 0)) {
                     /* Dag nab it.  */
@@ -647,7 +652,8 @@ postmap:
             if (zeroend > zeropage) {
                 if (type != OBJECT_MAPPED &&
                     type != OBJECT_INTERNAL &&
-                    type != OBJECT_USER) {
+                    type != OBJECT_USER &&
+                    type != OBJECT_VDSO) {
                     PAL_PTR mapat = DkVirtualMemoryAlloc((void *)zeropage, zeroend - zeropage,
                                                          0, c->prot);
                     if (__builtin_expect (!mapat, 0)) {
@@ -657,9 +663,9 @@ postmap:
                 }
 
 #if BOOKKEEP_INTERNAL_OBJ == 0
-                if (type != OBJECT_INTERNAL && type != OBJECT_USER)
+                if (type != OBJECT_INTERNAL && type != OBJECT_USER && type != OBJECT_VDSO)
 #else
-                if (type != OBJECT_USER)
+                if (type != OBJECT_USER && type != OBJECT_VDSO)
 #endif
                     bkeep_mmap((void *) zeropage, zeroend - zeropage, c->prot,
                                MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED|
@@ -1057,7 +1063,7 @@ static int __load_elf_object (struct shim_handle * file, void * addr,
         goto out;
     }
 
-    if (type != OBJECT_INTERNAL)
+    if (type != OBJECT_INTERNAL && type != OBJECT_VDSO)
         do_relocate_object(map);
 
     if (internal_map) {
@@ -1067,6 +1073,8 @@ static int __load_elf_object (struct shim_handle * file, void * addr,
 
     if (type == OBJECT_INTERNAL)
         internal_map = map;
+    if (type == OBJECT_VDSO)
+        vdso_map = map;
 
     if (type != OBJECT_REMAP) {
         if (file) {
@@ -1261,14 +1269,21 @@ do_lookup_map (ElfW(Sym) * ref, const char * undef_name,
 /* Inner part of the lookup functions.  We return a value > 0 if we
    found the symbol, the value 0 if nothing is found and < 0 if
    something bad happened.  */
-static int do_lookup (const char * undef_name, ElfW(Sym) * ref,
-                      struct sym_val * result)
+static ElfW(Sym) *
+__do_lookup (const char * undef_name, ElfW(Sym) * ref,
+             struct link_map * map)
 {
     const uint_fast32_t fast_hash = elf_fast_hash(undef_name);
     const long int hash = elf_hash(undef_name);
+    return do_lookup_map(ref, undef_name, fast_hash, hash, map);
+}
+
+static int do_lookup (const char * undef_name, ElfW(Sym) * ref,
+                      struct sym_val * result)
+{
     ElfW(Sym) *sym = NULL;
 
-    sym = do_lookup_map(ref, undef_name, fast_hash, hash, internal_map);
+    sym = __do_lookup(undef_name, ref, internal_map);
 
     if (!sym)
         return 0;
@@ -1463,7 +1478,7 @@ int remove_loaded_libraries (void)
 {
     struct link_map * map = loaded_libraries, * next_map = map->l_next;
     while (map) {
-        if (map->l_type != OBJECT_INTERNAL)
+        if (map->l_type != OBJECT_INTERNAL && map->l_type != OBJECT_VDSO)
             __remove_elf_object(map);
 
         map = next_map;
@@ -1473,6 +1488,107 @@ int remove_loaded_libraries (void)
     return 0;
 }
 
+/*
+ * libsysdb.so is loaded as shared library and load address for child may not match the one for
+ * parent. Just treat vdso page as user-program data and adjust function pointers for vdso
+ * functions after migration.
+ */
+static void * vdso_addr __attribute_migratable = NULL;
+static ElfW(Addr) * __vdso_shim_clock_gettime __attribute_migratable = NULL;
+static ElfW(Addr) * __vdso_shim_gettimeofday __attribute_migratable = NULL;
+static ElfW(Addr) * __vdso_shim_time __attribute_migratable = NULL;
+static ElfW(Addr) * __vdso_shim_getcpu __attribute_migratable = NULL;
+
+static const struct {
+    const char *name;
+    ElfW(Addr) value;
+    ElfW(Addr) ** func;
+} vsyms[] = {
+    {
+        .name = "__vdso_shim_clock_gettime",
+        .value = (ElfW(Addr))&__shim_clock_gettime,
+        .func = &__vdso_shim_clock_gettime,
+    },
+    {
+        .name = "__vdso_shim_gettimeofday",
+        .value = (ElfW(Addr))&__shim_gettimeofday,
+        .func = &__vdso_shim_gettimeofday,
+    },
+    {
+        .name = "__vdso_shim_time",
+        .value = (ElfW(Addr))&__shim_time,
+        .func = &__vdso_shim_time,
+    },
+    {
+        .name = "__vdso_shim_getcpu",
+        .value = (ElfW(Addr))&__shim_getcpu,
+        .func = &__vdso_shim_getcpu,
+    }
+};
+
+static int vdso_map_init(void)
+{
+    /*
+     * Allocate vdso page as user program allocated it.
+     * Using directly vdso code in LibOS causes trouble when emulating fork.
+     * In host child process, LibOS may or may not be loaded at the same address.
+     * When LibOS is loaded at different address, it may overlap with the old vDSO area.
+     */
+    void *addr = bkeep_unmapped_heap(
+        ALIGN_UP(vdso_so_size), PROT_READ | PROT_EXEC, 0, NULL, 0,
+        "linux-vdso.so.1");
+    if (addr == NULL)
+        return -ENOMEM;
+    assert(addr == ALIGN_UP(addr));
+
+    void *ret_addr = (void *)DkVirtualMemoryAlloc(
+        addr, ALIGN_UP(vdso_so_size), 0, PAL_PROT_READ | PAL_PROT_WRITE);
+    if (!ret_addr)
+        return -PAL_ERRNO;
+    assert(addr == ret_addr);
+
+    memcpy(addr, &vdso_so, vdso_so_size);
+    memset(addr + vdso_so_size, 0, ALIGN_UP(vdso_so_size) - vdso_so_size);
+    __load_elf_object(NULL, addr, OBJECT_VDSO, NULL);
+    vdso_map->l_name = "vDSO";
+
+    for (size_t i = 0; i < sizeof(vsyms)/sizeof(vsyms[0]); i++) {
+        ElfW(Sym) *sym = __do_lookup(vsyms[i].name, NULL, vdso_map);
+        if (sym == NULL) {
+            debug("vDSO: symbol value for %s not found\n", vsyms[i].name);
+            continue;
+        }
+        *vsyms[i].func = (ElfW(Addr)*)(vdso_map->l_addr + sym->st_value);
+        **vsyms[i].func = vsyms[i].value;
+    }
+
+    if (!DkVirtualMemoryProtect(addr, ALIGN_UP(vdso_so_size),
+                                PAL_PROT_READ | PAL_PROT_EXEC))
+            return -PAL_ERRNO;
+
+    vdso_addr = addr;
+    return 0;
+}
+
+int vdso_map_migrate(void)
+{
+    if (!vdso_addr)
+        return 0;
+
+    if (!DkVirtualMemoryProtect(vdso_addr, ALIGN_UP(vdso_so_size),
+                                PAL_PROT_READ | PAL_PROT_WRITE))
+            return -PAL_ERRNO;
+
+    /* adjust funcs to loaded address for newly loaded libsysdb */
+    for (size_t i = 0; i < sizeof(vsyms)/sizeof(vsyms[0]); i++)
+        **vsyms[i].func = vsyms[i].value;
+
+    if (!DkVirtualMemoryProtect(vdso_addr, ALIGN_UP(vdso_so_size),
+                                PAL_PROT_READ | PAL_PROT_EXEC))
+            return -PAL_ERRNO;
+    return 0;
+}
+
 int init_internal_map (void)
 {
     __load_elf_object(NULL, &__load_address, OBJECT_INTERNAL, NULL);
@@ -1562,14 +1678,18 @@ noreturn void execute_elf_object (struct shim_handle * exec,
                                   int * argcp, const char ** argp,
                                   ElfW(auxv_t) * auxp)
 {
+    int ret = vdso_map_init();
+    if (ret < 0) {
+        SYS_PRINTF("Could not initialize vDSO (error code = %d)", ret);
+        shim_clean(ret);
+    }
+
     struct link_map * exec_map = __search_map_by_handle(exec);
     assert(exec_map);
     assert((uintptr_t)argcp % 16 == 0);  /* stack must be 16B-aligned */
     assert((void*)argcp + sizeof(long) == argp || argp == NULL);
 
-    /* populate ELF aux vectors */
-    assert(REQUIRED_ELF_AUXV >= 7); /* stack allocated enough space */
-
+    assert(REQUIRED_ELF_AUXV >= 8); /* stack allocated enough space */
     auxp[0].a_type = AT_PHDR;
     auxp[0].a_un.a_val = (__typeof(auxp[0].a_un.a_val)) exec_map->l_phdr;
     auxp[1].a_type = AT_PHNUM;
@@ -1582,15 +1702,22 @@ noreturn void execute_elf_object (struct shim_handle * exec,
     auxp[4].a_un.a_val = interp_map ? interp_map->l_addr : 0;
     auxp[5].a_type = AT_RANDOM;
     auxp[5].a_un.a_val = 0; /* filled later */
-    auxp[6].a_type = AT_NULL;
-    auxp[6].a_un.a_val = 0;
+    if (vdso_addr) {
+        auxp[6].a_type = AT_SYSINFO_EHDR;
+        auxp[6].a_un.a_val = (uint64_t)vdso_addr;
+    } else {
+        auxp[6].a_type = AT_NULL;
+        auxp[6].a_un.a_val = 0;
+    }
+    auxp[7].a_type = AT_NULL;
+    auxp[7].a_un.a_val = 0;
 
     /* populate extra memory space for aux vector data */
     assert(REQUIRED_ELF_AUXV_SPACE >= 16); /* stack allocated enough space */
-    ElfW(Addr) auxp_extra = (ElfW(Addr))&auxp[7];
+    ElfW(Addr) auxp_extra = (ElfW(Addr))&auxp[8];
 
     ElfW(Addr) random = auxp_extra; /* random 16B for AT_RANDOM */
-    int ret = DkRandomBitsRead((PAL_PTR)random, 16);
+    ret = DkRandomBitsRead((PAL_PTR)random, 16);
     if (ret < 0) {
         debug("execute_elf_object: DkRandomBitsRead failed.\n");
         DkThreadExit();

+ 4 - 1
LibOS/shim/src/shim_init.c

@@ -30,6 +30,7 @@
 #include <shim_fs.h>
 #include <shim_ipc.h>
 #include <shim_profile.h>
+#include <shim_vdso.h>
 
 #include <pal.h>
 #include <pal_debug.h>
@@ -801,8 +802,10 @@ restore:
     shim_tcb_t * cur_tcb = shim_get_tls();
     struct shim_thread * cur_thread = (struct shim_thread *) cur_tcb->tp;
 
-    if (cur_tcb->context.regs && cur_tcb->context.regs->rsp)
+    if (cur_tcb->context.regs && cur_tcb->context.regs->rsp) {
+        vdso_map_migrate();
         restore_context(&cur_tcb->context);
+    }
 
     if (cur_thread->exec)
         execute_elf_object(cur_thread->exec, argcp, argp, auxp);

+ 2 - 0
LibOS/shim/src/vdso/.gitignore

@@ -0,0 +1,2 @@
+/vdso-data.c
+/vdso.so.dbg

+ 19 - 0
LibOS/shim/src/vdso/vdso-data.S

@@ -0,0 +1,19 @@
+	.section .rodata
+
+	.global vdso_so
+	.type vdso_so, @object
+	.align 4
+vdso_so:
+	.incbin "vdso/vdso.so"
+
+	.global vdso_so_end
+	.type vdso_so_end, @object
+	.align 4
+vdso_so_end:
+
+	.global vdso_so_size
+	.type vdso_so_size, @object
+	.size vdso_so_size, 8
+	.align 8
+vdso_so_size:
+	.quad vdso_so_end - vdso_so

+ 19 - 0
LibOS/shim/src/vdso/vdso-note.S

@@ -0,0 +1,19 @@
+	/* This .note section informs dynamic linker about vDSO */
+	.section .note.Linux, "a", @note
+
+	.balign 4
+	.long	6		/* namesz */
+	.long	4		/* descsz */
+	.long	0		/* type */
+	.string "Linux"	/* name */
+	.zero	2		/* padding for 4-byte alignment */
+	.long	267008	/* LINUX_VERSION_CODE */
+
+	.balign 4
+	.long	6		/* namesz */
+	.long	4		/* descsz */
+	.long	0x100	/* type */
+	.string "Linux"	/* name */
+	.zero	2		/* padding for 4-byte alignment */
+	.long	0		/* CONFIG_BUILD_SALT. 0 for now.
+					   TODO: make it compile-time configurable */

+ 63 - 0
LibOS/shim/src/vdso/vdso.c

@@ -0,0 +1,63 @@
+/* Copyright (C) 2018 Intel Corporation
+                      Isaku Yamahata <isaku.yamahata at gmail.com>
+                                     <isaku.yamahata at intel.com>
+   All Rights Reserved.
+
+   This file is part of Graphene Library OS.
+
+   Graphene Library OS is free software: you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation, either version 3 of the
+   License, or (at your option) any later version.
+
+   Graphene Library OS is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <shim_types.h>
+
+int (*__vdso_shim_clock_gettime)(clockid_t clock, struct timespec *t) = NULL;
+int (*__vdso_shim_gettimeofday)(struct timeval *tv, struct timezone *tz) = NULL;
+time_t (*__vdso_shim_time)(time_t *t) = NULL;
+long (*__vdso_shim_getcpu)(unsigned *cpu, struct getcpu_cache *unused) = NULL;
+
+
+int __vdso_clock_gettime(clockid_t clock, struct timespec *t)
+{
+    if (__vdso_shim_clock_gettime)
+        return (*__vdso_shim_clock_gettime)(clock, t);
+    return -ENOSYS;
+}
+int clock_gettime(clockid_t clock, struct timespec *t)
+    __attribute__((weak, alias("__vdso_clock_gettime")));
+
+int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+    if (__vdso_shim_gettimeofday)
+        return (*__vdso_shim_gettimeofday)(tv, tz);
+    return -ENOSYS;
+}
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+    __attribute__((weak, alias("__vdso_gettimeofday")));
+
+time_t __vdso_time(time_t *t)
+{
+    if (__vdso_shim_time)
+        return (*__vdso_shim_time)(t);
+    return -ENOSYS;
+}
+time_t time(time_t *t) __attribute__((weak, alias("__vdso_time")));
+
+long __vdso_getcpu(unsigned *cpu, struct getcpu_cache *unused)
+{
+    if (__vdso_shim_getcpu)
+        return (*__vdso_shim_getcpu)(cpu, unused);
+    return -ENOSYS;
+}
+long getcpu(unsigned *cpu, struct getcpu_cache *unused)
+    __attribute__((weak, alias("__vdso_getcpu")));

+ 82 - 0
LibOS/shim/src/vdso/vdso.lds

@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 Intel Corporation
+ *                    Isaku Yamahata <isaku.yamahata at gmail.com>
+ *                                   <isaku.yamahata at intel.com>
+ * All Rights Reserved.
+ * This file is part of Graphene Library OS.
+ *
+ * Graphene Library OS is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Graphene Library OS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Linker script for Graphene vDSO emulation
+ */
+
+PHDRS
+{
+        text            PT_LOAD         FLAGS(5) FILEHDR PHDRS;
+        dynamic         PT_DYNAMIC      FLAGS(4);
+        note            PT_NOTE         FLAGS(4);
+        eh_frame_header PT_GNU_EH_FRAME;
+}
+
+SECTIONS
+{
+        . = SIZEOF_HEADERS;
+        .hash : { *(.hash) } :text
+        .gnu.hash : { *(.gnu.hash) }
+        .dynsym : { *(.dynsym) }
+        .dynstr : { *(.dynstr) }
+        .gnu.version : { *(.gnu.version) }
+        .gnu.version_d : { *(.gnu.version_d) }
+        .gnu.version_r : { *(.gnu.version_r) }
+        .dynamic : { *(.dynamic) } :text :dynamic
+        .rodata : {
+                *(.rodata*)
+                *(.data*)
+                *(.sdata*)
+                *(.got.plt) *(.got)
+                *(.gnu.linkonce.d.*)
+                *(.bss*)
+                *(.dynbss*)
+                *(.gnu.linkonce.b.*)
+        } : text
+        .note : { *(.note.*) } :text :note
+        .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+        .eh_frame : { KEEP (*(.eh_frame)) } :text
+        .text   : { *(.text*) } : text = 0x909090
+
+        /DISCARD/ : {
+                *(.discard)
+                *(.discard.*)
+        }
+}
+
+VERSION {
+        LINUX_2.6 {
+        global:
+                clock_gettime;
+                __vdso_clock_gettime;
+                gettimeofday;
+                __vdso_gettimeofday;
+                getcpu;
+                __vdso_getcpu;
+                time;
+                __vdso_time;
+
+                __vdso_shim_clock_gettime;
+                __vdso_shim_gettimeofday;
+                __vdso_shim_getcpu;
+                __vdso_shim_time;
+        local: *;
+        };
+}

+ 1 - 0
Makefile.configs

@@ -10,3 +10,4 @@ endif
 ifeq ($(origin LD),default)
 LD	= ld
 endif
+OBJCOPY ?= objcopy

+ 8 - 2
Makefile.rules

@@ -69,13 +69,11 @@ CLEAN_FILES += generated_offsets.py generated_offsets.pyc
 quiet_cmd_ln_sf = [ $@ ]
       cmd_ln_sf = ln -sf $(abspath $<) $@
 
-
 cc-option = $(shell set -e; \
 	if ($(CC) -Werror $(1) -c -x c /dev/null -o /dev/null) >/dev/null 2>&1; \
 	then echo "$(1)"; \
 	fi)
 
-
 # .c
 quiet_cmd_cc_o_c = [ $@ ]
       cmd_cc_o_c = $(CC) $(CFLAGS) $(CFLAGS-$@) -c -o $@ $<
@@ -103,3 +101,11 @@ quiet_cmd_ar_so_o = [ $@ ]
 
 quiet_cmd_ar_a_o = [ $@ ]
       cmd_ar_a_o = $(AR) $(ARFLAGS) $(ARFLAGS-$@) $@ $^
+
+# LD only
+quiet_cmd_ld = [ $@ ]
+      cmd_ld = $(LD) $(LDFLAGS) $(LDFLAGS-$@) -o $@ $(filter-out %.map %.lds,$^)
+
+# OBJCOPY
+quiet_cmd_objcopy = [ $@ ]
+      cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS-$@) $< $@