summaryrefslogtreecommitdiffstats
path: root/arch/x86/vdso
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
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')
-rw-r--r--arch/x86/vdso/Makefile16
-rw-r--r--arch/x86/vdso/vdso-fakesections.c21
-rw-r--r--arch/x86/vdso/vdso2c.c116
-rw-r--r--arch/x86/vdso/vdso2c.h202
4 files changed, 126 insertions, 229 deletions
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 61b04fe36e66..5a4affe025e8 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -10,7 +10,7 @@ VDSO32-$(CONFIG_X86_32) := y
10VDSO32-$(CONFIG_COMPAT) := y 10VDSO32-$(CONFIG_COMPAT) := y
11 11
12# files to link into the vdso 12# files to link into the vdso
13vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vdso-fakesections.o 13vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
14 14
15# files to link into kernel 15# files to link into kernel
16obj-y += vma.o 16obj-y += vma.o
@@ -37,7 +37,8 @@ vdso_img_sodbg := $(vdso_img-y:%=vdso%.so.dbg)
37obj-y += $(vdso_img_objs) 37obj-y += $(vdso_img_objs)
38targets += $(vdso_img_cfiles) 38targets += $(vdso_img_cfiles)
39targets += $(vdso_img_sodbg) 39targets += $(vdso_img_sodbg)
40.SECONDARY: $(vdso_img-y:%=$(obj)/vdso-image-%.c) 40.SECONDARY: $(vdso_img-y:%=$(obj)/vdso-image-%.c) \
41 $(vdso_img-y:%=$(obj)/vdso%.so)
41 42
42export CPPFLAGS_vdso.lds += -P -C 43export CPPFLAGS_vdso.lds += -P -C
43 44
@@ -54,10 +55,10 @@ hostprogs-y += vdso2c
54 55
55quiet_cmd_vdso2c = VDSO2C $@ 56quiet_cmd_vdso2c = VDSO2C $@
56define cmd_vdso2c 57define cmd_vdso2c
57 $(obj)/vdso2c $< $@ 58 $(obj)/vdso2c $< $(<:%.dbg=%) $@
58endef 59endef
59 60
60$(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso2c FORCE 61$(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso%.so $(obj)/vdso2c FORCE
61 $(call if_changed,vdso2c) 62 $(call if_changed,vdso2c)
62 63
63# 64#
@@ -113,6 +114,10 @@ $(obj)/%-x32.o: $(obj)/%.o FORCE
113 114
114targets += vdsox32.lds $(vobjx32s-y) 115targets += vdsox32.lds $(vobjx32s-y)
115 116
117$(obj)/%.so: OBJCOPYFLAGS := -S
118$(obj)/%.so: $(obj)/%.so.dbg
119 $(call if_changed,objcopy)
120
116$(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE 121$(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE
117 $(call if_changed,vdso) 122 $(call if_changed,vdso)
118 123
@@ -134,7 +139,7 @@ override obj-dirs = $(dir $(obj)) $(obj)/vdso32/
134 139
135targets += vdso32/vdso32.lds 140targets += vdso32/vdso32.lds
136targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o) 141targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o)
137targets += vdso32/vclock_gettime.o vdso32/vdso-fakesections.o 142targets += vdso32/vclock_gettime.o
138 143
139$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%) 144$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%)
140 145
@@ -156,7 +161,6 @@ $(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
156$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \ 161$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
157 $(obj)/vdso32/vdso32.lds \ 162 $(obj)/vdso32/vdso32.lds \
158 $(obj)/vdso32/vclock_gettime.o \ 163 $(obj)/vdso32/vclock_gettime.o \
159 $(obj)/vdso32/vdso-fakesections.o \
160 $(obj)/vdso32/note.o \ 164 $(obj)/vdso32/note.o \
161 $(obj)/vdso32/%.o 165 $(obj)/vdso32/%.o
162 $(call if_changed,vdso) 166 $(call if_changed,vdso)
diff --git a/arch/x86/vdso/vdso-fakesections.c b/arch/x86/vdso/vdso-fakesections.c
deleted file mode 100644
index aa5fbfab20a5..000000000000
--- a/arch/x86/vdso/vdso-fakesections.c
+++ /dev/null
@@ -1,21 +0,0 @@
1/*
2 * Copyright 2014 Andy Lutomirski
3 * Subject to the GNU Public License, v.2
4 *
5 * String table for loadable section headers. See vdso2c.h for why
6 * this exists.
7 */
8
9const char fake_shstrtab[] __attribute__((section(".fake_shstrtab"))) =
10 ".hash\0"
11 ".dynsym\0"
12 ".dynstr\0"
13 ".gnu.version\0"
14 ".gnu.version_d\0"
15 ".dynamic\0"
16 ".rodata\0"
17 ".fake_shstrtab\0" /* Yay, self-referential code. */
18 ".note\0"
19 ".eh_frame_hdr\0"
20 ".eh_frame\0"
21 ".text";
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;
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
index 2da32fbc46da..fd57829b30d8 100644
--- a/arch/x86/vdso/vdso2c.h
+++ b/arch/x86/vdso/vdso2c.h
@@ -4,128 +4,14 @@
4 * are built for 32-bit userspace. 4 * are built for 32-bit userspace.
5 */ 5 */
6 6
7/* 7static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
8 * We're writing a section table for a few reasons: 8 void *stripped_addr, size_t stripped_len,
9 *
10 * The Go runtime had a couple of bugs: it would read the section
11 * table to try to figure out how many dynamic symbols there were (it
12 * shouldn't have looked at the section table at all) and, if there
13 * were no SHT_SYNDYM section table entry, it would use an
14 * uninitialized value for the number of symbols. An empty DYNSYM
15 * table would work, but I see no reason not to write a valid one (and
16 * keep full performance for old Go programs). This hack is only
17 * needed on x86_64.
18 *
19 * The bug was introduced on 2012-08-31 by:
20 * https://code.google.com/p/go/source/detail?r=56ea40aac72b
21 * and was fixed on 2014-06-13 by:
22 * https://code.google.com/p/go/source/detail?r=fc1cd5e12595
23 *
24 * Binutils has issues debugging the vDSO: it reads the section table to
25 * find SHT_NOTE; it won't look at PT_NOTE for the in-memory vDSO, which
26 * would break build-id if we removed the section table. Binutils
27 * also requires that shstrndx != 0. See:
28 * https://sourceware.org/bugzilla/show_bug.cgi?id=17064
29 *
30 * elfutils might not look for PT_NOTE if there is a section table at
31 * all. I don't know whether this matters for any practical purpose.
32 *
33 * For simplicity, rather than hacking up a partial section table, we
34 * just write a mostly complete one. We omit non-dynamic symbols,
35 * though, since they're rather large.
36 *
37 * Once binutils gets fixed, we might be able to drop this for all but
38 * the 64-bit vdso, since build-id only works in kernel RPMs, and
39 * systems that update to new enough kernel RPMs will likely update
40 * binutils in sync. build-id has never worked for home-built kernel
41 * RPMs without manual symlinking, and I suspect that no one ever does
42 * that.
43 */
44struct BITSFUNC(fake_sections)
45{
46 ELF(Shdr) *table;
47 unsigned long table_offset;
48 int count, max_count;
49
50 int in_shstrndx;
51 unsigned long shstr_offset;
52 const char *shstrtab;
53 size_t shstrtab_len;
54
55 int out_shstrndx;
56};
57
58static unsigned int BITSFUNC(find_shname)(struct BITSFUNC(fake_sections) *out,
59 const char *name)
60{
61 const char *outname = out->shstrtab;
62 while (outname - out->shstrtab < out->shstrtab_len) {
63 if (!strcmp(name, outname))
64 return (outname - out->shstrtab) + out->shstr_offset;
65 outname += strlen(outname) + 1;
66 }
67
68 if (*name)
69 printf("Warning: could not find output name \"%s\"\n", name);
70 return out->shstr_offset + out->shstrtab_len - 1; /* Use a null. */
71}
72
73static void BITSFUNC(init_sections)(struct BITSFUNC(fake_sections) *out)
74{
75 if (!out->in_shstrndx)
76 fail("didn't find the fake shstrndx\n");
77
78 memset(out->table, 0, out->max_count * sizeof(ELF(Shdr)));
79
80 if (out->max_count < 1)
81 fail("we need at least two fake output sections\n");
82
83 PUT_LE(&out->table[0].sh_type, SHT_NULL);
84 PUT_LE(&out->table[0].sh_name, BITSFUNC(find_shname)(out, ""));
85
86 out->count = 1;
87}
88
89static void BITSFUNC(copy_section)(struct BITSFUNC(fake_sections) *out,
90 int in_idx, const ELF(Shdr) *in,
91 const char *name)
92{
93 uint64_t flags = GET_LE(&in->sh_flags);
94
95 bool copy = flags & SHF_ALLOC &&
96 (GET_LE(&in->sh_size) ||
97 (GET_LE(&in->sh_type) != SHT_RELA &&
98 GET_LE(&in->sh_type) != SHT_REL)) &&
99 strcmp(name, ".altinstructions") &&
100 strcmp(name, ".altinstr_replacement");
101
102 if (!copy)
103 return;
104
105 if (out->count >= out->max_count)
106 fail("too many copied sections (max = %d)\n", out->max_count);
107
108 if (in_idx == out->in_shstrndx)
109 out->out_shstrndx = out->count;
110
111 out->table[out->count] = *in;
112 PUT_LE(&out->table[out->count].sh_name,
113 BITSFUNC(find_shname)(out, name));
114
115 /* elfutils requires that a strtab have the correct type. */
116 if (!strcmp(name, ".fake_shstrtab"))
117 PUT_LE(&out->table[out->count].sh_type, SHT_STRTAB);
118
119 out->count++;
120}
121
122static void BITSFUNC(go)(void *addr, size_t len,
123 FILE *outfile, const char *name) 9 FILE *outfile, const char *name)
124{ 10{
125 int found_load = 0; 11 int found_load = 0;
126 unsigned long load_size = -1; /* Work around bogus warning */ 12 unsigned long load_size = -1; /* Work around bogus warning */
127 unsigned long data_size; 13 unsigned long mapping_size;
128 ELF(Ehdr) *hdr = (ELF(Ehdr) *)addr; 14 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr;
129 int i; 15 int i;
130 unsigned long j; 16 unsigned long j;
131 ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, 17 ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr,
@@ -134,9 +20,7 @@ static void BITSFUNC(go)(void *addr, size_t len,
134 const char *secstrings; 20 const char *secstrings;
135 INT_BITS syms[NSYMS] = {}; 21 INT_BITS syms[NSYMS] = {};
136 22
137 struct BITSFUNC(fake_sections) fake_sections = {}; 23 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_LE(&hdr->e_phoff));
138
139 ELF(Phdr) *pt = (ELF(Phdr) *)(addr + GET_LE(&hdr->e_phoff));
140 24
141 /* Walk the segment table. */ 25 /* Walk the segment table. */
142 for (i = 0; i < GET_LE(&hdr->e_phnum); i++) { 26 for (i = 0; i < GET_LE(&hdr->e_phnum); i++) {
@@ -154,14 +38,16 @@ static void BITSFUNC(go)(void *addr, size_t len,
154 load_size = GET_LE(&pt[i].p_memsz); 38 load_size = GET_LE(&pt[i].p_memsz);
155 found_load = 1; 39 found_load = 1;
156 } else if (GET_LE(&pt[i].p_type) == PT_DYNAMIC) { 40 } else if (GET_LE(&pt[i].p_type) == PT_DYNAMIC) {
157 dyn = addr + GET_LE(&pt[i].p_offset); 41 dyn = raw_addr + GET_LE(&pt[i].p_offset);
158 dyn_end = addr + GET_LE(&pt[i].p_offset) + 42 dyn_end = raw_addr + GET_LE(&pt[i].p_offset) +
159 GET_LE(&pt[i].p_memsz); 43 GET_LE(&pt[i].p_memsz);
160 } 44 }
161 } 45 }
162 if (!found_load) 46 if (!found_load)
163 fail("no PT_LOAD seg\n"); 47 fail("no PT_LOAD seg\n");
164 data_size = (load_size + 4095) / 4096 * 4096; 48
49 if (stripped_len < load_size)
50 fail("stripped input is too short\n");
165 51
166 /* Walk the dynamic table */ 52 /* Walk the dynamic table */
167 for (i = 0; dyn + i < dyn_end && 53 for (i = 0; dyn + i < dyn_end &&
@@ -173,11 +59,11 @@ static void BITSFUNC(go)(void *addr, size_t len,
173 } 59 }
174 60
175 /* Walk the section table */ 61 /* Walk the section table */
176 secstrings_hdr = addr + GET_LE(&hdr->e_shoff) + 62 secstrings_hdr = raw_addr + GET_LE(&hdr->e_shoff) +
177 GET_LE(&hdr->e_shentsize)*GET_LE(&hdr->e_shstrndx); 63 GET_LE(&hdr->e_shentsize)*GET_LE(&hdr->e_shstrndx);
178 secstrings = addr + GET_LE(&secstrings_hdr->sh_offset); 64 secstrings = raw_addr + GET_LE(&secstrings_hdr->sh_offset);
179 for (i = 0; i < GET_LE(&hdr->e_shnum); i++) { 65 for (i = 0; i < GET_LE(&hdr->e_shnum); i++) {
180 ELF(Shdr) *sh = addr + GET_LE(&hdr->e_shoff) + 66 ELF(Shdr) *sh = raw_addr + GET_LE(&hdr->e_shoff) +
181 GET_LE(&hdr->e_shentsize) * i; 67 GET_LE(&hdr->e_shentsize) * i;
182 if (GET_LE(&sh->sh_type) == SHT_SYMTAB) 68 if (GET_LE(&sh->sh_type) == SHT_SYMTAB)
183 symtab_hdr = sh; 69 symtab_hdr = sh;
@@ -190,7 +76,7 @@ static void BITSFUNC(go)(void *addr, size_t len,
190 if (!symtab_hdr) 76 if (!symtab_hdr)
191 fail("no symbol table\n"); 77 fail("no symbol table\n");
192 78
193 strtab_hdr = addr + GET_LE(&hdr->e_shoff) + 79 strtab_hdr = raw_addr + GET_LE(&hdr->e_shoff) +
194 GET_LE(&hdr->e_shentsize) * GET_LE(&symtab_hdr->sh_link); 80 GET_LE(&hdr->e_shentsize) * GET_LE(&symtab_hdr->sh_link);
195 81
196 /* Walk the symbol table */ 82 /* Walk the symbol table */
@@ -198,9 +84,9 @@ static void BITSFUNC(go)(void *addr, size_t len,
198 i < GET_LE(&symtab_hdr->sh_size) / GET_LE(&symtab_hdr->sh_entsize); 84 i < GET_LE(&symtab_hdr->sh_size) / GET_LE(&symtab_hdr->sh_entsize);
199 i++) { 85 i++) {
200 int k; 86 int k;
201 ELF(Sym) *sym = addr + GET_LE(&symtab_hdr->sh_offset) + 87 ELF(Sym) *sym = raw_addr + GET_LE(&symtab_hdr->sh_offset) +
202 GET_LE(&symtab_hdr->sh_entsize) * i; 88 GET_LE(&symtab_hdr->sh_entsize) * i;
203 const char *name = addr + GET_LE(&strtab_hdr->sh_offset) + 89 const char *name = raw_addr + GET_LE(&strtab_hdr->sh_offset) +
204 GET_LE(&sym->st_name); 90 GET_LE(&sym->st_name);
205 91
206 for (k = 0; k < NSYMS; k++) { 92 for (k = 0; k < NSYMS; k++) {
@@ -219,48 +105,7 @@ static void BITSFUNC(go)(void *addr, size_t len,
219 syms[k] = GET_LE(&sym->st_value); 105 syms[k] = GET_LE(&sym->st_value);
220 } 106 }
221 } 107 }
222
223 if (!strcmp(name, "fake_shstrtab")) {
224 ELF(Shdr) *sh;
225
226 fake_sections.in_shstrndx = GET_LE(&sym->st_shndx);
227 fake_sections.shstrtab = addr + GET_LE(&sym->st_value);
228 fake_sections.shstrtab_len = GET_LE(&sym->st_size);
229 sh = addr + GET_LE(&hdr->e_shoff) +
230 GET_LE(&hdr->e_shentsize) *
231 fake_sections.in_shstrndx;
232 fake_sections.shstr_offset = GET_LE(&sym->st_value) -
233 GET_LE(&sh->sh_addr);
234 }
235 }
236
237 /* Build the output section table. */
238 if (!syms[sym_VDSO_FAKE_SECTION_TABLE_START] ||
239 !syms[sym_VDSO_FAKE_SECTION_TABLE_END])
240 fail("couldn't find fake section table\n");
241 if ((syms[sym_VDSO_FAKE_SECTION_TABLE_END] -
242 syms[sym_VDSO_FAKE_SECTION_TABLE_START]) % sizeof(ELF(Shdr)))
243 fail("fake section table size isn't a multiple of sizeof(Shdr)\n");
244 fake_sections.table = addr + syms[sym_VDSO_FAKE_SECTION_TABLE_START];
245 fake_sections.table_offset = syms[sym_VDSO_FAKE_SECTION_TABLE_START];
246 fake_sections.max_count = (syms[sym_VDSO_FAKE_SECTION_TABLE_END] -
247 syms[sym_VDSO_FAKE_SECTION_TABLE_START]) /
248 sizeof(ELF(Shdr));
249
250 BITSFUNC(init_sections)(&fake_sections);
251 for (i = 0; i < GET_LE(&hdr->e_shnum); i++) {
252 ELF(Shdr) *sh = addr + GET_LE(&hdr->e_shoff) +
253 GET_LE(&hdr->e_shentsize) * i;
254 BITSFUNC(copy_section)(&fake_sections, i, sh,
255 secstrings + GET_LE(&sh->sh_name));
256 } 108 }
257 if (!fake_sections.out_shstrndx)
258 fail("didn't generate shstrndx?!?\n");
259
260 PUT_LE(&hdr->e_shoff, fake_sections.table_offset);
261 PUT_LE(&hdr->e_shentsize, sizeof(ELF(Shdr)));
262 PUT_LE(&hdr->e_shnum, fake_sections.count);
263 PUT_LE(&hdr->e_shstrndx, fake_sections.out_shstrndx);
264 109
265 /* Validate mapping addresses. */ 110 /* Validate mapping addresses. */
266 for (i = 0; i < sizeof(special_pages) / sizeof(special_pages[0]); i++) { 111 for (i = 0; i < sizeof(special_pages) / sizeof(special_pages[0]); i++) {
@@ -281,10 +126,12 @@ static void BITSFUNC(go)(void *addr, size_t len,
281 fail("vvar_begin must be a multiple of 4096\n"); 126 fail("vvar_begin must be a multiple of 4096\n");
282 127
283 if (!name) { 128 if (!name) {
284 fwrite(addr, load_size, 1, outfile); 129 fwrite(stripped_addr, stripped_len, 1, outfile);
285 return; 130 return;
286 } 131 }
287 132
133 mapping_size = (stripped_len + 4095) / 4096 * 4096;
134
288 fprintf(outfile, "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n\n"); 135 fprintf(outfile, "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n\n");
289 fprintf(outfile, "#include <linux/linkage.h>\n"); 136 fprintf(outfile, "#include <linux/linkage.h>\n");
290 fprintf(outfile, "#include <asm/page_types.h>\n"); 137 fprintf(outfile, "#include <asm/page_types.h>\n");
@@ -292,20 +139,21 @@ static void BITSFUNC(go)(void *addr, size_t len,
292 fprintf(outfile, "\n"); 139 fprintf(outfile, "\n");
293 fprintf(outfile, 140 fprintf(outfile,
294 "static unsigned char raw_data[%lu] __page_aligned_data = {", 141 "static unsigned char raw_data[%lu] __page_aligned_data = {",
295 data_size); 142 mapping_size);
296 for (j = 0; j < load_size; j++) { 143 for (j = 0; j < stripped_len; j++) {
297 if (j % 10 == 0) 144 if (j % 10 == 0)
298 fprintf(outfile, "\n\t"); 145 fprintf(outfile, "\n\t");
299 fprintf(outfile, "0x%02X, ", (int)((unsigned char *)addr)[j]); 146 fprintf(outfile, "0x%02X, ",
147 (int)((unsigned char *)stripped_addr)[j]);
300 } 148 }
301 fprintf(outfile, "\n};\n\n"); 149 fprintf(outfile, "\n};\n\n");
302 150
303 fprintf(outfile, "static struct page *pages[%lu];\n\n", 151 fprintf(outfile, "static struct page *pages[%lu];\n\n",
304 data_size / 4096); 152 mapping_size / 4096);
305 153
306 fprintf(outfile, "const struct vdso_image %s = {\n", name); 154 fprintf(outfile, "const struct vdso_image %s = {\n", name);
307 fprintf(outfile, "\t.data = raw_data,\n"); 155 fprintf(outfile, "\t.data = raw_data,\n");
308 fprintf(outfile, "\t.size = %lu,\n", data_size); 156 fprintf(outfile, "\t.size = %lu,\n", mapping_size);
309 fprintf(outfile, "\t.text_mapping = {\n"); 157 fprintf(outfile, "\t.text_mapping = {\n");
310 fprintf(outfile, "\t\t.name = \"[vdso]\",\n"); 158 fprintf(outfile, "\t\t.name = \"[vdso]\",\n");
311 fprintf(outfile, "\t\t.pages = pages,\n"); 159 fprintf(outfile, "\t\t.pages = pages,\n");