Update vDSO examples for 32-bit systems
cover Update vDSO examples for 32-bit systems
We have useful code in the 32-bit x86 vDSO now; update the sample code.
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.
Andy Lutomirski (2):
doc,vdso: Rename vdso_test.c to vdso_standalone_test_x86.c doc,vdso: Make vDSO examples more portable
Documentation/vDSO/parse_vdso.c | 59 ++++++------ Documentation/vDSO/vdso_standalone_test_x86.c | 128 ++++++++++++++++++++++++++ Documentation/vDSO/vdso_test.c | 103 +++++---------------- 3 files changed, 181 insertions(+), 109 deletions(-) create mode 100644 Documentation/vDSO/vdso_standalone_test_x86.c
Signature · 1 line
1.9.3
PATCH 1/2 doc,vdso: Rename vdso_test.c to vdso_standalone_test_x86.c
This thing is hopelessly x86_64-specific: it's an example of how to access the vDSO without any runtime support at all.
--- 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
Documentation/vDSO/vdso_standalone_test_x86.c new file +111 -0
@@ -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; + asmvolatile ("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) +{ + asmvolatile ("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" + );
Documentation/vDSO/vdso_test.c deleted +0 -111
111 lines not on this page · raw message
Signature · 1 line
1.9.3
PATCH 2/2 doc,vdso: Make vDSO examples more portable
In reply to Andy LutomirskiThis 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.
--- 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
Documentation/vDSO/parse_vdso.c +32 -27
@@ -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_infouintptr_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 ) {
Documentation/vDSO/vdso_standalone_test_x86.c +31 -14
73 lines not on this page · raw message
Documentation/vDSO/vdso_test.c new file +50 -0
50 lines not on this page · raw message
Signature · 1 line
1.9.3