1
+ /*
2
+ * vdso2c - A vdso image preparation tool
3
+ * Copyright (c) 2014 Andy Lutomirski and others
4
+ * Licensed under the GPL v2
5
+ *
6
+ * vdso2c requires stripped and unstripped input. It would be trivial
7
+ * to fully strip the input in here, but, for reasons described below,
8
+ * we need to write a section table. Doing this is more or less
9
+ * equivalent to dropping all non-allocatable sections, but it's
10
+ * easier to let objcopy handle that instead of doing it ourselves.
11
+ * If we ever need to do something fancier than what objcopy provides,
12
+ * it would be straightforward to add here.
13
+ *
14
+ * We're keep a section table for a few reasons:
15
+ *
16
+ * The Go runtime had a couple of bugs: it would read the section
17
+ * table to try to figure out how many dynamic symbols there were (it
18
+ * shouldn't have looked at the section table at all) and, if there
19
+ * were no SHT_SYNDYM section table entry, it would use an
20
+ * uninitialized value for the number of symbols. An empty DYNSYM
21
+ * table would work, but I see no reason not to write a valid one (and
22
+ * keep full performance for old Go programs). This hack is only
23
+ * needed on x86_64.
24
+ *
25
+ * The bug was introduced on 2012-08-31 by:
26
+ * https://code.google.com/p/go/source/detail?r=56ea40aac72b
27
+ * and was fixed on 2014-06-13 by:
28
+ * https://code.google.com/p/go/source/detail?r=fc1cd5e12595
29
+ *
30
+ * Binutils has issues debugging the vDSO: it reads the section table to
31
+ * find SHT_NOTE; it won't look at PT_NOTE for the in-memory vDSO, which
32
+ * would break build-id if we removed the section table. Binutils
33
+ * also requires that shstrndx != 0. See:
34
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=17064
35
+ *
36
+ * elfutils might not look for PT_NOTE if there is a section table at
37
+ * all. I don't know whether this matters for any practical purpose.
38
+ *
39
+ * For simplicity, rather than hacking up a partial section table, we
40
+ * just write a mostly complete one. We omit non-dynamic symbols,
41
+ * though, since they're rather large.
42
+ *
43
+ * Once binutils gets fixed, we might be able to drop this for all but
44
+ * the 64-bit vdso, since build-id only works in kernel RPMs, and
45
+ * systems that update to new enough kernel RPMs will likely update
46
+ * binutils in sync. build-id has never worked for home-built kernel
47
+ * RPMs without manual symlinking, and I suspect that no one ever does
48
+ * that.
49
+ */
50
+
1
51
#include <inttypes.h>
2
52
#include <stdint.h>
3
53
#include <unistd.h>
@@ -20,9 +70,9 @@ const char *outfilename;
20
70
21
71
/* Symbols that we need in vdso2c. */
22
72
enum {
73
+ sym_vvar_start ,
23
74
sym_vvar_page ,
24
75
sym_hpet_page ,
25
- sym_end_mapping ,
26
76
sym_VDSO_FAKE_SECTION_TABLE_START ,
27
77
sym_VDSO_FAKE_SECTION_TABLE_END ,
28
78
};
@@ -38,9 +88,9 @@ struct vdso_sym {
38
88
};
39
89
40
90
struct vdso_sym required_syms [] = {
91
+ [sym_vvar_start ] = {"vvar_start" , true},
41
92
[sym_vvar_page ] = {"vvar_page" , true},
42
93
[sym_hpet_page ] = {"hpet_page" , true},
43
- [sym_end_mapping ] = {"end_mapping" , true},
44
94
[sym_VDSO_FAKE_SECTION_TABLE_START ] = {
45
95
"VDSO_FAKE_SECTION_TABLE_START" , false
46
96
},
@@ -61,7 +111,8 @@ static void fail(const char *format, ...)
61
111
va_start (ap , format );
62
112
fprintf (stderr , "Error: " );
63
113
vfprintf (stderr , format , ap );
64
- unlink (outfilename );
114
+ if (outfilename )
115
+ unlink (outfilename );
65
116
exit (1 );
66
117
va_end (ap );
67
118
}
@@ -96,9 +147,11 @@ extern void bad_put_le(void);
96
147
97
148
#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))
98
149
99
- #define BITSFUNC3 (name , bits ) name##bits
100
- #define BITSFUNC2 (name , bits ) BITSFUNC3(name, bits)
101
- #define BITSFUNC (name ) BITSFUNC2(name, ELF_BITS)
150
+ #define BITSFUNC3 (name , bits , suffix ) name##bits##suffix
151
+ #define BITSFUNC2 (name , bits , suffix ) BITSFUNC3(name, bits, suffix)
152
+ #define BITSFUNC (name ) BITSFUNC2(name, ELF_BITS, )
153
+
154
+ #define INT_BITS BITSFUNC2(int, ELF_BITS, _t)
102
155
103
156
#define ELF_BITS_XFORM2 (bits , x ) Elf##bits##_##x
104
157
#define ELF_BITS_XFORM (bits , x ) ELF_BITS_XFORM2(bits, x)
@@ -112,38 +165,61 @@ extern void bad_put_le(void);
112
165
#include "vdso2c.h"
113
166
#undef ELF_BITS
114
167
115
- static void go (void * addr , size_t len , FILE * outfile , const char * name )
168
+ static void go (void * raw_addr , size_t raw_len ,
169
+ void * stripped_addr , size_t stripped_len ,
170
+ FILE * outfile , const char * name )
116
171
{
117
- Elf64_Ehdr * hdr = (Elf64_Ehdr * )addr ;
172
+ Elf64_Ehdr * hdr = (Elf64_Ehdr * )raw_addr ;
118
173
119
174
if (hdr -> e_ident [EI_CLASS ] == ELFCLASS64 ) {
120
- go64 (addr , len , outfile , name );
175
+ go64 (raw_addr , raw_len , stripped_addr , stripped_len ,
176
+ outfile , name );
121
177
} else if (hdr -> e_ident [EI_CLASS ] == ELFCLASS32 ) {
122
- go32 (addr , len , outfile , name );
178
+ go32 (raw_addr , raw_len , stripped_addr , stripped_len ,
179
+ outfile , name );
123
180
} else {
124
181
fail ("unknown ELF class\n" );
125
182
}
126
183
}
127
184
185
+ static void map_input (const char * name , void * * addr , size_t * len , int prot )
186
+ {
187
+ off_t tmp_len ;
188
+
189
+ int fd = open (name , O_RDONLY );
190
+ if (fd == -1 )
191
+ err (1 , "%s" , name );
192
+
193
+ tmp_len = lseek (fd , 0 , SEEK_END );
194
+ if (tmp_len == (off_t )- 1 )
195
+ err (1 , "lseek" );
196
+ * len = (size_t )tmp_len ;
197
+
198
+ * addr = mmap (NULL , tmp_len , prot , MAP_PRIVATE , fd , 0 );
199
+ if (* addr == MAP_FAILED )
200
+ err (1 , "mmap" );
201
+
202
+ close (fd );
203
+ }
204
+
128
205
int main (int argc , char * * argv )
129
206
{
130
- int fd ;
131
- off_t len ;
132
- void * addr ;
207
+ size_t raw_len , stripped_len ;
208
+ void * raw_addr , * stripped_addr ;
133
209
FILE * outfile ;
134
210
char * name , * tmp ;
135
211
int namelen ;
136
212
137
- if (argc != 3 ) {
138
- printf ("Usage: vdso2c INPUT OUTPUT\n" );
213
+ if (argc != 4 ) {
214
+ printf ("Usage: vdso2c RAW_INPUT STRIPPED_INPUT OUTPUT\n" );
139
215
return 1 ;
140
216
}
141
217
142
218
/*
143
219
* Figure out the struct name. If we're writing to a .so file,
144
220
* generate raw output insted.
145
221
*/
146
- name = strdup (argv [2 ]);
222
+ name = strdup (argv [3 ]);
147
223
namelen = strlen (name );
148
224
if (namelen >= 3 && !strcmp (name + namelen - 3 , ".so" )) {
149
225
name = NULL ;
@@ -159,26 +235,18 @@ int main(int argc, char **argv)
159
235
* tmp = '_' ;
160
236
}
161
237
162
- fd = open (argv [1 ], O_RDONLY );
163
- if (fd == -1 )
164
- err (1 , "%s" , argv [1 ]);
165
-
166
- len = lseek (fd , 0 , SEEK_END );
167
- if (len == (off_t )- 1 )
168
- err (1 , "lseek" );
169
-
170
- addr = mmap (NULL , len , PROT_READ | PROT_WRITE , MAP_PRIVATE , fd , 0 );
171
- if (addr == MAP_FAILED )
172
- err (1 , "mmap" );
238
+ map_input (argv [1 ], & raw_addr , & raw_len , PROT_READ );
239
+ map_input (argv [2 ], & stripped_addr , & stripped_len , PROT_READ );
173
240
174
- outfilename = argv [2 ];
241
+ outfilename = argv [3 ];
175
242
outfile = fopen (outfilename , "w" );
176
243
if (!outfile )
177
244
err (1 , "%s" , argv [2 ]);
178
245
179
- go (addr , ( size_t ) len , outfile , name );
246
+ go (raw_addr , raw_len , stripped_addr , stripped_len , outfile , name );
180
247
181
- munmap (addr , len );
248
+ munmap (raw_addr , raw_len );
249
+ munmap (stripped_addr , stripped_len );
182
250
fclose (outfile );
183
251
184
252
return 0 ;
0 commit comments