diff options
| author | Andy Lutomirski <luto@amacapital.net> | 2014-06-12 20:53:10 -0400 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2014-06-12 22:01:24 -0400 |
| commit | 4ebbefd6b93c34d6da0d950b1d2e0dcca2f1e6ef (patch) | |
| tree | 5d94b4e1dd26d5c1a4ce2866486936333ca2e96f | |
| parent | 6e8f21584a30ba6ce73cfef34f316d5bf3fadaab (diff) | |
x86/vdso/doc: Make vDSO examples more portable
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>
Link: http://lkml.kernel.org/r/62b701fc44b79f118ac2b2d64d19965fc5c291fb.1402620737.git.luto@amacapital.net
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
| -rw-r--r-- | Documentation/vDSO/parse_vdso.c | 67 | ||||
| -rw-r--r-- | Documentation/vDSO/vdso_standalone_test_x86.c | 45 | ||||
| -rw-r--r-- | Documentation/vDSO/vdso_test.c | 52 |
3 files changed, 123 insertions, 41 deletions
diff --git a/Documentation/vDSO/parse_vdso.c b/Documentation/vDSO/parse_vdso.c index 85870208edcf..1dbb4b87268f 100644 --- a/Documentation/vDSO/parse_vdso.c +++ b/Documentation/vDSO/parse_vdso.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * parse_vdso.c: Linux reference vDSO parser | 2 | * parse_vdso.c: Linux reference vDSO parser |
| 3 | * Written by Andrew Lutomirski, 2011. | 3 | * Written by Andrew Lutomirski, 2011-2014. |
| 4 | * | 4 | * |
| 5 | * This code is meant to be linked in to various programs that run on Linux. | 5 | * This code is meant to be linked in to various programs that run on Linux. |
| 6 | * As such, it is available with as few restrictions as possible. This file | 6 | * As such, it is available with as few restrictions as possible. This file |
| @@ -11,13 +11,14 @@ | |||
| 11 | * it starts a program. It works equally well in statically and dynamically | 11 | * it starts a program. It works equally well in statically and dynamically |
| 12 | * linked binaries. | 12 | * linked binaries. |
| 13 | * | 13 | * |
| 14 | * This code is tested on x86_64. In principle it should work on any 64-bit | 14 | * This code is tested on x86. In principle it should work on any |
| 15 | * architecture that has a vDSO. | 15 | * architecture that has a vDSO. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <stdbool.h> | 18 | #include <stdbool.h> |
| 19 | #include <stdint.h> | 19 | #include <stdint.h> |
| 20 | #include <string.h> | 20 | #include <string.h> |
| 21 | #include <limits.h> | ||
| 21 | #include <elf.h> | 22 | #include <elf.h> |
| 22 | 23 | ||
| 23 | /* | 24 | /* |
| @@ -45,11 +46,18 @@ extern void *vdso_sym(const char *version, const char *name); | |||
| 45 | 46 | ||
| 46 | 47 | ||
| 47 | /* And here's the code. */ | 48 | /* And here's the code. */ |
| 48 | 49 | #ifndef ELF_BITS | |
| 49 | #ifndef __x86_64__ | 50 | # if ULONG_MAX > 0xffffffffUL |
| 50 | # error Not yet ported to non-x86_64 architectures | 51 | # define ELF_BITS 64 |
| 52 | # else | ||
| 53 | # define ELF_BITS 32 | ||
| 54 | # endif | ||
| 51 | #endif | 55 | #endif |
| 52 | 56 | ||
| 57 | #define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x | ||
| 58 | #define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x) | ||
| 59 | #define ELF(x) ELF_BITS_XFORM(ELF_BITS, x) | ||
| 60 | |||
| 53 | static struct vdso_info | 61 | static struct vdso_info |
| 54 | { | 62 | { |
| 55 | bool valid; | 63 | bool valid; |
| @@ -59,14 +67,14 @@ static struct vdso_info | |||
| 59 | uintptr_t load_offset; /* load_addr - recorded vaddr */ | 67 | uintptr_t load_offset; /* load_addr - recorded vaddr */ |
| 60 | 68 | ||
| 61 | /* Symbol table */ | 69 | /* Symbol table */ |
| 62 | Elf64_Sym *symtab; | 70 | ELF(Sym) *symtab; |
| 63 | const char *symstrings; | 71 | const char *symstrings; |
| 64 | Elf64_Word *bucket, *chain; | 72 | ELF(Word) *bucket, *chain; |
| 65 | Elf64_Word nbucket, nchain; | 73 | ELF(Word) nbucket, nchain; |
| 66 | 74 | ||
| 67 | /* Version table */ | 75 | /* Version table */ |
| 68 | Elf64_Versym *versym; | 76 | ELF(Versym) *versym; |
| 69 | Elf64_Verdef *verdef; | 77 | ELF(Verdef) *verdef; |
| 70 | } vdso_info; | 78 | } vdso_info; |
| 71 | 79 | ||
| 72 | /* Straight from the ELF specification. */ | 80 | /* Straight from the ELF specification. */ |
| @@ -92,9 +100,14 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) | |||
| 92 | 100 | ||
| 93 | vdso_info.load_addr = base; | 101 | vdso_info.load_addr = base; |
| 94 | 102 | ||
| 95 | Elf64_Ehdr *hdr = (Elf64_Ehdr*)base; | 103 | ELF(Ehdr) *hdr = (ELF(Ehdr)*)base; |
| 96 | Elf64_Phdr *pt = (Elf64_Phdr*)(vdso_info.load_addr + hdr->e_phoff); | 104 | if (hdr->e_ident[EI_CLASS] != |
| 97 | Elf64_Dyn *dyn = 0; | 105 | (ELF_BITS == 32 ? ELFCLASS32 : ELFCLASS64)) { |
| 106 | return; /* Wrong ELF class -- check ELF_BITS */ | ||
| 107 | } | ||
| 108 | |||
| 109 | ELF(Phdr) *pt = (ELF(Phdr)*)(vdso_info.load_addr + hdr->e_phoff); | ||
| 110 | ELF(Dyn) *dyn = 0; | ||
| 98 | 111 | ||
| 99 | /* | 112 | /* |
| 100 | * We need two things from the segment table: the load offset | 113 | * We need two things from the segment table: the load offset |
| @@ -108,7 +121,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) | |||
| 108 | + (uintptr_t)pt[i].p_offset | 121 | + (uintptr_t)pt[i].p_offset |
| 109 | - (uintptr_t)pt[i].p_vaddr; | 122 | - (uintptr_t)pt[i].p_vaddr; |
| 110 | } else if (pt[i].p_type == PT_DYNAMIC) { | 123 | } else if (pt[i].p_type == PT_DYNAMIC) { |
| 111 | dyn = (Elf64_Dyn*)(base + pt[i].p_offset); | 124 | dyn = (ELF(Dyn)*)(base + pt[i].p_offset); |
| 112 | } | 125 | } |
| 113 | } | 126 | } |
| 114 | 127 | ||
| @@ -118,7 +131,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) | |||
| 118 | /* | 131 | /* |
| 119 | * Fish out the useful bits of the dynamic table. | 132 | * Fish out the useful bits of the dynamic table. |
| 120 | */ | 133 | */ |
| 121 | Elf64_Word *hash = 0; | 134 | ELF(Word) *hash = 0; |
| 122 | vdso_info.symstrings = 0; | 135 | vdso_info.symstrings = 0; |
| 123 | vdso_info.symtab = 0; | 136 | vdso_info.symtab = 0; |
| 124 | vdso_info.versym = 0; | 137 | vdso_info.versym = 0; |
| @@ -131,22 +144,22 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) | |||
| 131 | + vdso_info.load_offset); | 144 | + vdso_info.load_offset); |
| 132 | break; | 145 | break; |
| 133 | case DT_SYMTAB: | 146 | case DT_SYMTAB: |
| 134 | vdso_info.symtab = (Elf64_Sym *) | 147 | vdso_info.symtab = (ELF(Sym) *) |
| 135 | ((uintptr_t)dyn[i].d_un.d_ptr | 148 | ((uintptr_t)dyn[i].d_un.d_ptr |
| 136 | + vdso_info.load_offset); | 149 | + vdso_info.load_offset); |
| 137 | break; | 150 | break; |
| 138 | case DT_HASH: | 151 | case DT_HASH: |
| 139 | hash = (Elf64_Word *) | 152 | hash = (ELF(Word) *) |
| 140 | ((uintptr_t)dyn[i].d_un.d_ptr | 153 | ((uintptr_t)dyn[i].d_un.d_ptr |
| 141 | + vdso_info.load_offset); | 154 | + vdso_info.load_offset); |
| 142 | break; | 155 | break; |
| 143 | case DT_VERSYM: | 156 | case DT_VERSYM: |
| 144 | vdso_info.versym = (Elf64_Versym *) | 157 | vdso_info.versym = (ELF(Versym) *) |
| 145 | ((uintptr_t)dyn[i].d_un.d_ptr | 158 | ((uintptr_t)dyn[i].d_un.d_ptr |
| 146 | + vdso_info.load_offset); | 159 | + vdso_info.load_offset); |
| 147 | break; | 160 | break; |
| 148 | case DT_VERDEF: | 161 | case DT_VERDEF: |
| 149 | vdso_info.verdef = (Elf64_Verdef *) | 162 | vdso_info.verdef = (ELF(Verdef) *) |
| 150 | ((uintptr_t)dyn[i].d_un.d_ptr | 163 | ((uintptr_t)dyn[i].d_un.d_ptr |
| 151 | + vdso_info.load_offset); | 164 | + vdso_info.load_offset); |
| 152 | break; | 165 | break; |
| @@ -168,8 +181,8 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) | |||
| 168 | vdso_info.valid = true; | 181 | vdso_info.valid = true; |
| 169 | } | 182 | } |
| 170 | 183 | ||
| 171 | static bool vdso_match_version(Elf64_Versym ver, | 184 | static bool vdso_match_version(ELF(Versym) ver, |
| 172 | const char *name, Elf64_Word hash) | 185 | const char *name, ELF(Word) hash) |
| 173 | { | 186 | { |
| 174 | /* | 187 | /* |
| 175 | * This is a helper function to check if the version indexed by | 188 | * This is a helper function to check if the version indexed by |
| @@ -188,7 +201,7 @@ static bool vdso_match_version(Elf64_Versym ver, | |||
| 188 | 201 | ||
| 189 | /* First step: find the version definition */ | 202 | /* First step: find the version definition */ |
| 190 | ver &= 0x7fff; /* Apparently bit 15 means "hidden" */ | 203 | ver &= 0x7fff; /* Apparently bit 15 means "hidden" */ |
| 191 | Elf64_Verdef *def = vdso_info.verdef; | 204 | ELF(Verdef) *def = vdso_info.verdef; |
| 192 | while(true) { | 205 | while(true) { |
| 193 | if ((def->vd_flags & VER_FLG_BASE) == 0 | 206 | if ((def->vd_flags & VER_FLG_BASE) == 0 |
| 194 | && (def->vd_ndx & 0x7fff) == ver) | 207 | && (def->vd_ndx & 0x7fff) == ver) |
| @@ -197,11 +210,11 @@ static bool vdso_match_version(Elf64_Versym ver, | |||
| 197 | if (def->vd_next == 0) | 210 | if (def->vd_next == 0) |
| 198 | return false; /* No definition. */ | 211 | return false; /* No definition. */ |
| 199 | 212 | ||
| 200 | def = (Elf64_Verdef *)((char *)def + def->vd_next); | 213 | def = (ELF(Verdef) *)((char *)def + def->vd_next); |
| 201 | } | 214 | } |
| 202 | 215 | ||
| 203 | /* Now figure out whether it matches. */ | 216 | /* Now figure out whether it matches. */ |
| 204 | Elf64_Verdaux *aux = (Elf64_Verdaux*)((char *)def + def->vd_aux); | 217 | ELF(Verdaux) *aux = (ELF(Verdaux)*)((char *)def + def->vd_aux); |
| 205 | return def->vd_hash == hash | 218 | return def->vd_hash == hash |
| 206 | && !strcmp(name, vdso_info.symstrings + aux->vda_name); | 219 | |
