1
1
/*
2
2
* parse_vdso.c: Linux reference vDSO parser
3
- * Written by Andrew Lutomirski, 2011.
3
+ * Written by Andrew Lutomirski, 2011-2014 .
4
4
*
5
5
* This code is meant to be linked in to various programs that run on Linux.
6
6
* As such, it is available with as few restrictions as possible. This file
11
11
* it starts a program. It works equally well in statically and dynamically
12
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
15
* architecture that has a vDSO.
16
16
*/
17
17
18
18
#include <stdbool.h>
19
19
#include <stdint.h>
20
20
#include <string.h>
21
+ #include <limits.h>
21
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
48
/* And here's the code. */
48
-
49
- #ifndef __x86_64__
50
- # error Not yet ported to non-x86_64 architectures
49
+ #ifndef ELF_BITS
50
+ # if ULONG_MAX > 0xffffffffUL
51
+ # define ELF_BITS 64
52
+ # else
53
+ # define ELF_BITS 32
54
+ # endif
51
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
61
static struct vdso_info
54
62
{
55
63
bool valid ;
@@ -59,14 +67,14 @@ static struct vdso_info
59
67
uintptr_t load_offset ; /* load_addr - recorded vaddr */
60
68
61
69
/* Symbol table */
62
- Elf64_Sym * symtab ;
70
+ ELF ( Sym ) * symtab ;
63
71
const char * symstrings ;
64
- Elf64_Word * bucket , * chain ;
65
- Elf64_Word nbucket , nchain ;
72
+ ELF ( Word ) * bucket , * chain ;
73
+ ELF ( Word ) nbucket , nchain ;
66
74
67
75
/* Version table */
68
- Elf64_Versym * versym ;
69
- Elf64_Verdef * verdef ;
76
+ ELF ( Versym ) * versym ;
77
+ ELF ( Verdef ) * verdef ;
70
78
} vdso_info ;
71
79
72
80
/* Straight from the ELF specification. */
@@ -92,9 +100,14 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
92
100
93
101
vdso_info .load_addr = base ;
94
102
95
- Elf64_Ehdr * hdr = (Elf64_Ehdr * )base ;
96
- Elf64_Phdr * pt = (Elf64_Phdr * )(vdso_info .load_addr + hdr -> e_phoff );
97
- Elf64_Dyn * dyn = 0 ;
103
+ ELF (Ehdr ) * hdr = (ELF (Ehdr )* )base ;
104
+ if (hdr -> e_ident [EI_CLASS ] !=
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
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
121
+ (uintptr_t )pt [i ].p_offset
109
122
- (uintptr_t )pt [i ].p_vaddr ;
110
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
132
* Fish out the useful bits of the dynamic table.
120
133
*/
121
- Elf64_Word * hash = 0 ;
134
+ ELF ( Word ) * hash = 0 ;
122
135
vdso_info .symstrings = 0 ;
123
136
vdso_info .symtab = 0 ;
124
137
vdso_info .versym = 0 ;
@@ -131,22 +144,22 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
131
144
+ vdso_info .load_offset );
132
145
break ;
133
146
case DT_SYMTAB :
134
- vdso_info .symtab = (Elf64_Sym * )
147
+ vdso_info .symtab = (ELF ( Sym ) * )
135
148
((uintptr_t )dyn [i ].d_un .d_ptr
136
149
+ vdso_info .load_offset );
137
150
break ;
138
151
case DT_HASH :
139
- hash = (Elf64_Word * )
152
+ hash = (ELF ( Word ) * )
140
153
((uintptr_t )dyn [i ].d_un .d_ptr
141
154
+ vdso_info .load_offset );
142
155
break ;
143
156
case DT_VERSYM :
144
- vdso_info .versym = (Elf64_Versym * )
157
+ vdso_info .versym = (ELF ( Versym ) * )
145
158
((uintptr_t )dyn [i ].d_un .d_ptr
146
159
+ vdso_info .load_offset );
147
160
break ;
148
161
case DT_VERDEF :
149
- vdso_info .verdef = (Elf64_Verdef * )
162
+ vdso_info .verdef = (ELF ( Verdef ) * )
150
163
((uintptr_t )dyn [i ].d_un .d_ptr
151
164
+ vdso_info .load_offset );
152
165
break ;
@@ -168,8 +181,8 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
168
181
vdso_info .valid = true;
169
182
}
170
183
171
- static bool vdso_match_version (Elf64_Versym ver ,
172
- const char * name , Elf64_Word hash )
184
+ static bool vdso_match_version (ELF ( Versym ) ver ,
185
+ const char * name , ELF ( Word ) hash )
173
186
{
174
187
/*
175
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
202
/* First step: find the version definition */
190
203
ver &= 0x7fff ; /* Apparently bit 15 means "hidden" */
191
- Elf64_Verdef * def = vdso_info .verdef ;
204
+ ELF ( Verdef ) * def = vdso_info .verdef ;
192
205
while (true) {
193
206
if ((def -> vd_flags & VER_FLG_BASE ) == 0
194
207
&& (def -> vd_ndx & 0x7fff ) == ver )
@@ -197,11 +210,11 @@ static bool vdso_match_version(Elf64_Versym ver,
197
210
if (def -> vd_next == 0 )
198
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
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
218
return def -> vd_hash == hash
206
219
&& !strcmp (name , vdso_info .symstrings + aux -> vda_name );
207
220
}
@@ -213,10 +226,10 @@ void *vdso_sym(const char *version, const char *name)
213
226
return 0 ;
214
227
215
228
ver_hash = elf_hash (version );
216
- Elf64_Word chain = vdso_info .bucket [elf_hash (name ) % vdso_info .nbucket ];
229
+ ELF ( Word ) chain = vdso_info .bucket [elf_hash (name ) % vdso_info .nbucket ];
217
230
218
231
for (; chain != STN_UNDEF ; chain = vdso_info .chain [chain ]) {
219
- Elf64_Sym * sym = & vdso_info .symtab [chain ];
232
+ ELF ( Sym ) * sym = & vdso_info .symtab [chain ];
220
233
221
234
/* Check for a defined global or weak function w/ right name. */
222
235
if (ELF64_ST_TYPE (sym -> st_info ) != STT_FUNC )
@@ -243,7 +256,7 @@ void *vdso_sym(const char *version, const char *name)
243
256
244
257
void vdso_init_from_auxv (void * auxv )
245
258
{
246
- Elf64_auxv_t * elf_auxv = auxv ;
259
+ ELF ( auxv_t ) * elf_auxv = auxv ;
247
260
for (int i = 0 ; elf_auxv [i ].a_type != AT_NULL ; i ++ )
248
261
{
249
262
if (elf_auxv [i ].a_type == AT_SYSINFO_EHDR ) {
0 commit comments