aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/vdso/vdso2c.c
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-07-10 21:13:16 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2014-07-11 19:58:07 -0400
commitda861e18ecccb5c126b9eb95ff720ce082a46286 (patch)
tree0ebd971bbfd8e659890ffff572e01d9c171ba58d /arch/x86/vdso/vdso2c.c
parente6577a7ce99a506b587bcd1d2cd803cb45119557 (diff)
x86, vdso: Get rid of the fake section mechanism
Now that we can tolerate extra things dangling off the end of the vdso image, we can strip the vdso the old fashioned way rather than using an overcomplicated custom stripping algorithm. This is a partial reversion of: 6f121e5 x86, vdso: Reimplement vdso.so preparation in build-time C Signed-off-by: Andy Lutomirski <luto@amacapital.net> Link: http://lkml.kernel.org/r/50e01ed6dcc0575d20afd782f9fe98d5ee3e2d8a.1405040914.git.luto@amacapital.net Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/vdso/vdso2c.c')
-rw-r--r--arch/x86/vdso/vdso2c.c116
1 files changed, 91 insertions, 25 deletions
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c
index 22c54d04bced..8627db24a7f6 100644
--- a/arch/x86/vdso/vdso2c.c
+++ b/arch/x86/vdso/vdso2c.c
@@ -1,3 +1,53 @@
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#include <inttypes.h> 51#include <inttypes.h>
2#include <stdint.h> 52#include <stdint.h>
3#include <unistd.h> 53#include <unistd.h>
@@ -61,7 +111,8 @@ static void fail(const char *format, ...)
61 va_start(ap, format); 111 va_start(ap, format);
62 fprintf(stderr, "Error: "); 112 fprintf(stderr, "Error: ");
63 vfprintf(stderr, format, ap); 113 vfprintf(stderr, format, ap);
64 unlink(outfilename); 114 if (outfilename)
115 unlink(outfilename);
65 exit(1); 116 exit(1);
66 va_end(ap); 117 va_end(ap);
67} 118}
@@ -114,30 +165,53 @@ extern void bad_put_le(void);
114#include "vdso2c.h" 165#include "vdso2c.h"
115#undef ELF_BITS 166#undef ELF_BITS
116 167
117static void go(void *addr, size_t len, FILE *outfile, const char *name) 168static void go(void *raw_addr, size_t raw_len,
169 void *stripped_addr, size_t stripped_len,
170 FILE *outfile, const char *name)
118{ 171{
119 Elf64_Ehdr *hdr = (Elf64_Ehdr *)addr; 172 Elf64_Ehdr *hdr = (Elf64_Ehdr *)raw_addr;
120 173
121 if (hdr->e_ident[EI_CLASS] == ELFCLASS64) { 174 if (hdr->e_ident[EI_CLASS] == ELFCLASS64) {
122 go64(addr, len, outfile, name); 175 go64(raw_addr, raw_len, stripped_addr, stripped_len,
176 outfile, name);
123 } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) { 177 } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) {
124 go32(addr, len, outfile, name); 178 go32(raw_addr, raw_len, stripped_addr, stripped_len,
179 outfile, name);
125 } else { 180 } else {
126 fail("unknown ELF class\n"); 181 fail("unknown ELF class\n");
127 } 182 }
128} 183}
129 184
185static 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
130int main(int argc, char **argv) 205int main(int argc, char **argv)
131{ 206{
132 int fd; 207 size_t raw_len, stripped_len;
133 off_t len; 208 void *raw_addr, *stripped_addr;
134 void *addr;
135 FILE *outfile; 209 FILE *outfile;
136 char *name, *tmp; 210 char *name, *tmp;
137 int namelen; 211 int namelen;
138 212
139 if (argc != 3) { 213 if (argc != 4) {
140 printf("Usage: vdso2c INPUT OUTPUT\n"); 214 printf("Usage: vdso2c RAW_INPUT STRIPPED_INPUT OUTPUT\n");
141 return 1; 215 return 1;
142 } 216 }
143 217
@@ -145,7 +219,7 @@ int main(int argc, char **argv)
145 * Figure out the struct name. If we're writing to a .so file, 219 * Figure out the struct name. If we're writing to a .so file,
146 * generate raw output insted. 220 * generate raw output insted.
147 */ 221 */
148 name = strdup(argv[2]); 222 name = strdup(argv[3]);
149 namelen = strlen(name); 223 namelen = strlen(name);
150 if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) { 224 if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) {
151 name = NULL; 225 name = NULL;
@@ -161,26 +235,18 @@ int main(int argc, char **argv)
161 *tmp = '_'; 235 *tmp = '_';
162 } 236 }
163 237
164 fd = open(argv[1], O_RDONLY); 238 map_input(argv[1], &raw_addr, &raw_len, PROT_READ);
165 if (fd == -1) 239 map_input(argv[2], &stripped_addr, &stripped_len, PROT_READ);
166 err(1, "%s", argv[1]);
167
168 len = lseek(fd, 0, SEEK_END);
169 if (len == (off_t)-1)
170 err(1, "lseek");
171
172 addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
173 if (addr == MAP_FAILED)
174 err(1, "mmap");
175 240
176 outfilename = argv[2]; 241 outfilename = argv[3];
177 outfile = fopen(outfilename, "w"); 242 outfile = fopen(outfilename, "w");
178 if (!outfile) 243 if (!outfile)
179 err(1, "%s", argv[2]); 244 err(1, "%s", argv[2]);
180 245
181 go(addr, (size_t)len, outfile, name); 246 go(raw_addr, raw_len, stripped_addr, stripped_len, outfile, name);
182 247
183 munmap(addr, len); 248 munmap(raw_addr, raw_len);
249 munmap(stripped_addr, stripped_len);
184 fclose(outfile); 250 fclose(outfile);
185 251
186 return 0; 252 return 0;