diff options
author | Andy Lutomirski <luto@amacapital.net> | 2014-06-18 18:59:48 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2014-06-19 18:45:12 -0400 |
commit | bfad381c0d1e19cae8461e105d8d4387dd2a14fe (patch) | |
tree | c4f4fba23ad53bfe9c6f99c4c9156716fa3fa5c5 /arch/x86 | |
parent | c1979c370273fd9f7326ffa27a63b9ddb0f495f4 (diff) |
x86/vdso: Improve the fake section headers
Fully stripping the vDSO has other unfortunate side effects:
- binutils is unable to find ELF notes without a SHT_NOTE section.
- Even elfutils has trouble: it can find ELF notes without a section
table at all, but if a section table is present, it won't look for
PT_NOTE.
- gdb wants section names to match between stripped DSOs and their
symbols; otherwise it will corrupt symbol addresses.
We're also breaking the rules: section 0 is supposed to be SHT_NULL.
Fix these problems by building a better fake section table. While
we're at it, we might as well let buggy Go versions keep working well
by giving the SHT_DYNSYM entry the correct size.
This is a bit unfortunate: it adds quite a bit of size to the vdso
image.
If/when binutils improves and the improved versions become widespread,
it would be worth considering dropping most of this.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
Link: http://lkml.kernel.org/r/0e546a5eeaafdf1840e6ee654a55c1e727c26663.1403129369.git.luto@amacapital.net
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/vdso/Makefile | 4 | ||||
-rw-r--r-- | arch/x86/vdso/vdso-fakesections.c | 44 | ||||
-rw-r--r-- | arch/x86/vdso/vdso-layout.lds.S | 40 | ||||
-rw-r--r-- | arch/x86/vdso/vdso.lds.S | 2 | ||||
-rw-r--r-- | arch/x86/vdso/vdso2c.c | 31 | ||||
-rw-r--r-- | arch/x86/vdso/vdso2c.h | 180 | ||||
-rw-r--r-- | arch/x86/vdso/vdso32/vdso-fakesections.c | 1 | ||||
-rw-r--r-- | arch/x86/vdso/vdsox32.lds.S | 2 |
8 files changed, 237 insertions, 67 deletions
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile index 3c0809a0631f..2c1ca98eb612 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile | |||
@@ -11,7 +11,6 @@ VDSO32-$(CONFIG_COMPAT) := y | |||
11 | 11 | ||
12 | # files to link into the vdso | 12 | # files to link into the vdso |
13 | vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vdso-fakesections.o | 13 | vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vdso-fakesections.o |
14 | vobjs-nox32 := vdso-fakesections.o | ||
15 | 14 | ||
16 | # files to link into kernel | 15 | # files to link into kernel |
17 | obj-y += vma.o | 16 | obj-y += vma.o |
@@ -134,7 +133,7 @@ override obj-dirs = $(dir $(obj)) $(obj)/vdso32/ | |||
134 | 133 | ||
135 | targets += vdso32/vdso32.lds | 134 | targets += vdso32/vdso32.lds |
136 | targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o) | 135 | targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o) |
137 | targets += vdso32/vclock_gettime.o | 136 | targets += vdso32/vclock_gettime.o vdso32/vdso-fakesections.o |
138 | 137 | ||
139 | $(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%) | 138 | $(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%) |
140 | 139 | ||
@@ -155,6 +154,7 @@ $(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) | |||
155 | $(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \ | 154 | $(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \ |
156 | $(obj)/vdso32/vdso32.lds \ | 155 | $(obj)/vdso32/vdso32.lds \ |
157 | $(obj)/vdso32/vclock_gettime.o \ | 156 | $(obj)/vdso32/vclock_gettime.o \ |
157 | $(obj)/vdso32/vdso-fakesections.o \ | ||
158 | $(obj)/vdso32/note.o \ | 158 | $(obj)/vdso32/note.o \ |
159 | $(obj)/vdso32/%.o | 159 | $(obj)/vdso32/%.o |
160 | $(call if_changed,vdso) | 160 | $(call if_changed,vdso) |
diff --git a/arch/x86/vdso/vdso-fakesections.c b/arch/x86/vdso/vdso-fakesections.c index cb8a8d72c24b..56927a7e4977 100644 --- a/arch/x86/vdso/vdso-fakesections.c +++ b/arch/x86/vdso/vdso-fakesections.c | |||
@@ -2,31 +2,23 @@ | |||
2 | * Copyright 2014 Andy Lutomirski | 2 | * Copyright 2014 Andy Lutomirski |
3 | * Subject to the GNU Public License, v.2 | 3 | * Subject to the GNU Public License, v.2 |
4 | * | 4 | * |
5 | * Hack to keep broken Go programs working. | 5 | * String table for loadable section headers. See vdso2c.h for why |
6 | * | 6 | * this exists. |
7 | * The Go runtime had a couple of bugs: it would read the section table to try | ||
8 | * to figure out how many dynamic symbols there were (it shouldn't have looked | ||
9 | * at the section table at all) and, if there were no SHT_SYNDYM section table | ||
10 | * entry, it would use an uninitialized value for the number of symbols. As a | ||
11 | * workaround, we supply a minimal section table. vdso2c will adjust the | ||
12 | * in-memory image so that "vdso_fake_sections" becomes the section table. | ||
13 | * | ||
14 | * The bug was introduced by: | ||
15 | * https://code.google.com/p/go/source/detail?r=56ea40aac72b (2012-08-31) | ||
16 | * and is being addressed in the Go runtime in this issue: | ||
17 | * https://code.google.com/p/go/issues/detail?id=8197 | ||
18 | */ | 7 | */ |
19 | 8 | ||
20 | #ifndef __x86_64__ | 9 | const char fake_shstrtab[] __attribute__((section(".fake_shstrtab"))) = |
21 | #error This hack is specific to the 64-bit vDSO | 10 | ".hash\0" |
22 | #endif | 11 | ".dynsym\0" |
23 | 12 | ".dynstr\0" | |
24 | #include <linux/elf.h> | 13 | ".gnu.version\0" |
25 | 14 | ".gnu.version_d\0" | |
26 | extern const __visible struct elf64_shdr vdso_fake_sections[]; | 15 | ".dynamic\0" |
27 | const __visible struct elf64_shdr vdso_fake_sections[] = { | 16 | ".rodata\0" |
28 | { | 17 | ".fake_shstrtab\0" /* Yay, self-referential code. */ |
29 | .sh_type = SHT_DYNSYM, | 18 | ".note\0" |
30 | .sh_entsize = sizeof(Elf64_Sym), | 19 | ".data\0" |
31 | } | 20 | ".altinstructions\0" |
32 | }; | 21 | ".altinstr_replacement\0" |
22 | ".eh_frame_hdr\0" | ||
23 | ".eh_frame\0" | ||
24 | ".text"; | ||
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S index c84166cbcd28..e4cbc2145bab 100644 --- a/arch/x86/vdso/vdso-layout.lds.S +++ b/arch/x86/vdso/vdso-layout.lds.S | |||
@@ -6,6 +6,16 @@ | |||
6 | * This script controls its layout. | 6 | * This script controls its layout. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #if defined(BUILD_VDSO64) | ||
10 | # define SHDR_SIZE 64 | ||
11 | #elif defined(BUILD_VDSO32) || defined(BUILD_VDSOX32) | ||
12 | # define SHDR_SIZE 40 | ||
13 | #else | ||
14 | # error unknown VDSO target | ||
15 | #endif | ||
16 | |||
17 | #define NUM_FAKE_SHDRS 16 | ||
18 | |||
9 | SECTIONS | 19 | SECTIONS |
10 | { | 20 | { |
11 | . = SIZEOF_HEADERS; | 21 | . = SIZEOF_HEADERS; |
@@ -25,15 +35,29 @@ SECTIONS | |||
25 | 35 | ||
26 | .dynamic : { *(.dynamic) } :text :dynamic | 36 | .dynamic : { *(.dynamic) } :text :dynamic |
27 | 37 | ||
28 | .rodata : { *(.rodata*) } :text | 38 | .rodata : { |
39 | *(.rodata*) | ||
40 | |||
41 | /* | ||
42 | * Ideally this would live in a C file, but that won't | ||
43 | * work cleanly for x32 until we start building the x32 | ||
44 | * C code using an x32 toolchain. | ||
45 | */ | ||
46 | VDSO_FAKE_SECTION_TABLE_START = .; | ||
47 | . = . + NUM_FAKE_SHDRS * SHDR_SIZE; | ||
48 | VDSO_FAKE_SECTION_TABLE_END = .; | ||
49 | } :text | ||
50 | |||
51 | .fake_shstrtab : { *(.fake_shstrtab) } :text | ||
52 | |||
29 | .data : { | 53 | .data : { |
30 | *(.data*) | 54 | *(.data*) |
31 | *(.sdata*) | 55 | *(.sdata*) |
32 | *(.got.plt) *(.got) | 56 | *(.got.plt) *(.got) |
33 | *(.gnu.linkonce.d.*) | 57 | *(.gnu.linkonce.d.*) |
34 | *(.bss*) | 58 | *(.bss*) |
35 | *(.dynbss*) | 59 | *(.dynbss*) |
36 | *(.gnu.linkonce.b.*) | 60 | *(.gnu.linkonce.b.*) |
37 | } | 61 | } |
38 | 62 | ||
39 | .altinstructions : { *(.altinstructions) } | 63 | .altinstructions : { *(.altinstructions) } |
diff --git a/arch/x86/vdso/vdso.lds.S b/arch/x86/vdso/vdso.lds.S index 75e3404c83b1..6807932643c2 100644 --- a/arch/x86/vdso/vdso.lds.S +++ b/arch/x86/vdso/vdso.lds.S | |||
@@ -6,6 +6,8 @@ | |||
6 | * the DSO. | 6 | * the DSO. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define BUILD_VDSO64 | ||
10 | |||
9 | #include "vdso-layout.lds.S" | 11 | #include "vdso-layout.lds.S" |
10 | 12 | ||
11 | /* | 13 | /* |
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c index 734389976cc0..238dbe82776e 100644 --- a/arch/x86/vdso/vdso2c.c +++ b/arch/x86/vdso/vdso2c.c | |||
@@ -23,6 +23,8 @@ enum { | |||
23 | sym_vvar_page, | 23 | sym_vvar_page, |
24 | sym_hpet_page, | 24 | sym_hpet_page, |
25 | sym_end_mapping, | 25 | sym_end_mapping, |
26 | sym_VDSO_FAKE_SECTION_TABLE_START, | ||
27 | sym_VDSO_FAKE_SECTION_TABLE_END, | ||
26 | }; | 28 | }; |
27 | 29 | ||
28 | const int special_pages[] = { | 30 | const int special_pages[] = { |
@@ -30,15 +32,26 @@ const int special_pages[] = { | |||
30 | sym_hpet_page, | 32 | sym_hpet_page, |
31 | }; | 33 | }; |
32 | 34 | ||
33 | char const * const required_syms[] = { | 35 | struct vdso_sym { |
34 | [sym_vvar_page] = "vvar_page", | 36 | const char *name; |
35 | [sym_hpet_page] = "hpet_page", | 37 | bool export; |
36 | [sym_end_mapping] = "end_mapping", | 38 | }; |
37 | "VDSO32_NOTE_MASK", | 39 | |
38 | "VDSO32_SYSENTER_RETURN", | 40 | struct vdso_sym required_syms[] = { |
39 | "__kernel_vsyscall", | 41 | [sym_vvar_page] = {"vvar_page", true}, |
40 | "__kernel_sigreturn", | 42 | [sym_hpet_page] = {"hpet_page", true}, |
41 | "__kernel_rt_sigreturn", | 43 | [sym_end_mapping] = {"end_mapping", true}, |
44 | [sym_VDSO_FAKE_SECTION_TABLE_START] = { | ||
45 | "VDSO_FAKE_SECTION_TABLE_START", false | ||
46 | }, | ||
47 | [sym_VDSO_FAKE_SECTION_TABLE_END] = { | ||
48 | "VDSO_FAKE_SECTION_TABLE_END", false | ||
49 | }, | ||
50 | {"VDSO32_NOTE_MASK", true}, | ||
51 | {"VDSO32_SYSENTER_RETURN", true}, | ||
52 | {"__kernel_vsyscall", true}, | ||
53 | {"__kernel_sigreturn", true}, | ||
54 | {"__kernel_rt_sigreturn", true}, | ||
42 | }; | 55 | }; |
43 | 56 | ||
44 | __attribute__((format(printf, 1, 2))) __attribute__((noreturn)) | 57 | __attribute__((format(printf, 1, 2))) __attribute__((noreturn)) |
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h index 8e185ce39e69..f01ed4bde880 100644 --- a/arch/x86/vdso/vdso2c.h +++ b/arch/x86/vdso/vdso2c.h | |||
@@ -4,6 +4,116 @@ | |||
4 | * are built for 32-bit userspace. | 4 | * are built for 32-bit userspace. |
5 | */ | 5 | */ |
6 | 6 | ||
7 | /* | ||
8 | * We're writing a section table for a few reasons: | ||
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 | */ | ||
44 | struct 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 | |||
58 | static 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 | |||
73 | static 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 | |||
89 | static 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 | |||
97 | if (!copy) | ||
98 | return; | ||
99 | |||
100 | if (out->count >= out->max_count) | ||
101 | fail("too many copied sections (max = %d)\n", out->max_count); | ||
102 | |||
103 | if (in_idx == out->in_shstrndx) | ||
104 | out->out_shstrndx = out->count; | ||
105 | |||
106 | out->table[out->count] = *in; | ||
107 | PUT_LE(&out->table[out->count].sh_name, | ||
108 | BITSFUNC(find_shname)(out, name)); | ||
109 | |||
110 | /* elfutils requires that a strtab have the correct type. */ | ||
111 | if (!strcmp(name, ".fake_shstrtab")) | ||
112 | PUT_LE(&out->table[out->count].sh_type, SHT_STRTAB); | ||
113 | |||
114 | out->count++; | ||
115 | } | ||
116 | |||
7 | static void BITSFUNC(go)(void *addr, size_t len, | 117 | static void BITSFUNC(go)(void *addr, size_t len, |
8 | FILE *outfile, const char *name) | 118 | FILE *outfile, const char *name) |
9 | { | 119 | { |
@@ -19,7 +129,7 @@ static void BITSFUNC(go)(void *addr, size_t len, | |||
19 | const char *secstrings; | 129 | const char *secstrings; |
20 | uint64_t syms[NSYMS] = {}; | 130 | uint64_t syms[NSYMS] = {}; |
21 | 131 | ||
22 | uint64_t fake_sections_value = 0, fake_sections_size = 0; | 132 | struct BITSFUNC(fake_sections) fake_sections = {}; |
23 | 133 | ||
24 | ELF(Phdr) *pt = (ELF(Phdr) *)(addr + GET_LE(&hdr->e_phoff)); | 134 | ELF(Phdr) *pt = (ELF(Phdr) *)(addr + GET_LE(&hdr->e_phoff)); |
25 | 135 | ||
@@ -89,23 +199,57 @@ static void BITSFUNC(go)(void *addr, size_t len, | |||
89 | GET_LE(&sym->st_name); | 199 | GET_LE(&sym->st_name); |
90 | 200 | ||
91 | for (k = 0; k < NSYMS; k++) { | 201 | for (k = 0; k < NSYMS; k++) { |
92 | if (!strcmp(name, required_syms[k])) { | 202 | if (!strcmp(name, required_syms[k].name)) { |
93 | if (syms[k]) { | 203 | if (syms[k]) { |
94 | fail("duplicate symbol %s\n", | 204 | fail("duplicate symbol %s\n", |
95 | required_syms[k]); | 205 | required_syms[k].name); |
96 | } | 206 | } |
97 | syms[k] = GET_LE(&sym->st_value); | 207 | syms[k] = GET_LE(&sym->st_value); |
98 | } | 208 | } |
99 | } | 209 | } |
100 | 210 | ||
101 | if (!strcmp(name, "vdso_fake_sections")) { | 211 | if (!strcmp(name, "fake_shstrtab")) { |
102 | if (fake_sections_value) | 212 | ELF(Shdr) *sh; |
103 | fail("duplicate vdso_fake_sections\n"); | 213 | |
104 | fake_sections_value = GET_LE(&sym->st_value); | 214 | fake_sections.in_shstrndx = GET_LE(&sym->st_shndx); |
105 | fake_sections_size = GET_LE(&sym->st_size); | 215 | fake_sections.shstrtab = addr + GET_LE(&sym->st_value); |
216 | fake_sections.shstrtab_len = GET_LE(&sym->st_size); | ||
217 | sh = addr + GET_LE(&hdr->e_shoff) + | ||
218 | GET_LE(&hdr->e_shentsize) * | ||
219 | fake_sections.in_shstrndx; | ||
220 | fake_sections.shstr_offset = GET_LE(&sym->st_value) - | ||
221 | GET_LE(&sh->sh_addr); | ||
106 | } | 222 | } |
107 | } | 223 | } |
108 | 224 | ||
225 | /* Build the output section table. */ | ||
226 | if (!syms[sym_VDSO_FAKE_SECTION_TABLE_START] || | ||
227 | !syms[sym_VDSO_FAKE_SECTION_TABLE_END]) | ||
228 | fail("couldn't find fake section table\n"); | ||
229 | if ((syms[sym_VDSO_FAKE_SECTION_TABLE_END] - | ||
230 | syms[sym_VDSO_FAKE_SECTION_TABLE_START]) % sizeof(ELF(Shdr))) | ||
231 | fail("fake section table size isn't a multiple of sizeof(Shdr)\n"); | ||
232 | fake_sections.table = addr + syms[sym_VDSO_FAKE_SECTION_TABLE_START]; | ||
233 | fake_sections.table_offset = syms[sym_VDSO_FAKE_SECTION_TABLE_START]; | ||
234 | fake_sections.max_count = (syms[sym_VDSO_FAKE_SECTION_TABLE_END] - | ||
235 | syms[sym_VDSO_FAKE_SECTION_TABLE_START]) / | ||
236 | sizeof(ELF(Shdr)); | ||
237 | |||
238 | BITSFUNC(init_sections)(&fake_sections); | ||
239 | for (i = 0; i < GET_LE(&hdr->e_shnum); i++) { | ||
240 | ELF(Shdr) *sh = addr + GET_LE(&hdr->e_shoff) + | ||
241 | GET_LE(&hdr->e_shentsize) * i; | ||
242 | BITSFUNC(copy_section)(&fake_sections, i, sh, | ||
243 | secstrings + GET_LE(&sh->sh_name)); | ||
244 | } | ||
245 | if (!fake_sections.out_shstrndx) | ||
246 | fail("didn't generate shstrndx?!?\n"); | ||
247 | |||
248 | PUT_LE(&hdr->e_shoff, fake_sections.table_offset); | ||
249 | PUT_LE(&hdr->e_shentsize, sizeof(ELF(Shdr))); | ||
250 | PUT_LE(&hdr->e_shnum, fake_sections.count); | ||
251 | PUT_LE(&hdr->e_shstrndx, fake_sections.out_shstrndx); | ||
252 | |||
109 | /* Validate mapping addresses. */ | 253 | /* Validate mapping addresses. */ |
110 | for (i = 0; i < sizeof(special_pages) / sizeof(special_pages[0]); i++) { | 254 | for (i = 0; i < sizeof(special_pages) / sizeof(special_pages[0]); i++) { |
111 | if (!syms[i]) | 255 | if (!syms[i]) |
@@ -113,25 +257,17 @@ static void BITSFUNC(go)(void *addr, size_t len, | |||
113 | 257 | ||
114 | if (syms[i] % 4096) | 258 | if (syms[i] % 4096) |
115 | fail("%s must be a multiple of 4096\n", | 259 | fail("%s must be a multiple of 4096\n", |
116 | required_syms[i]); | 260 | required_syms[i].name); |
117 | if (syms[i] < data_size) | 261 | if (syms[i] < data_size) |
118 | fail("%s must be after the text mapping\n", | 262 | fail("%s must be after the text mapping\n", |
119 | required_syms[i]); | 263 | required_syms[i].name); |
120 | if (syms[sym_end_mapping] < syms[i] + 4096) | 264 | if (syms[sym_end_mapping] < syms[i] + 4096) |
121 | fail("%s overruns end_mapping\n", required_syms[i]); | 265 | fail("%s overruns end_mapping\n", |
266 | required_syms[i].name); | ||
122 | } | 267 | } |
123 | if (syms[sym_end_mapping] % 4096) | 268 | if (syms[sym_end_mapping] % 4096) |
124 | fail("end_mapping must be a multiple of 4096\n"); | 269 | fail("end_mapping must be a multiple of 4096\n"); |
125 | 270 | ||
126 | /* Remove sections or use fakes */ | ||
127 | if (fake_sections_size % sizeof(ELF(Shdr))) | ||
128 | fail("vdso_fake_sections size is not a multiple of %ld\n", | ||
129 | (long)sizeof(ELF(Shdr))); | ||
130 | PUT_LE(&hdr->e_shoff, fake_sections_value); | ||
131 | PUT_LE(&hdr->e_shentsize, fake_sections_value ? sizeof(ELF(Shdr)) : 0); | ||
132 | PUT_LE(&hdr->e_shnum, fake_sections_size / sizeof(ELF(Shdr))); | ||
133 | PUT_LE(&hdr->e_shstrndx, SHN_UNDEF); | ||
134 | |||
135 | if (!name) { | 271 | if (!name) { |
136 | fwrite(addr, load_size, 1, outfile); | 272 | fwrite(addr, load_size, 1, outfile); |
137 | return; | 273 | return; |
@@ -169,9 +305,9 @@ static void BITSFUNC(go)(void *addr, size_t len, | |||
169 | (unsigned long)GET_LE(&alt_sec->sh_size)); | 305 | (unsigned long)GET_LE(&alt_sec->sh_size)); |
170 | } | 306 | } |
171 | for (i = 0; i < NSYMS; i++) { | 307 | for (i = 0; i < NSYMS; i++) { |
172 | if (syms[i]) | 308 | if (required_syms[i].export && syms[i]) |
173 | fprintf(outfile, "\t.sym_%s = 0x%" PRIx64 ",\n", | 309 | fprintf(outfile, "\t.sym_%s = 0x%" PRIx64 ",\n", |
174 | required_syms[i], syms[i]); | 310 | required_syms[i].name, syms[i]); |
175 | } | 311 | } |
176 | fprintf(outfile, "};\n"); | 312 | fprintf(outfile, "};\n"); |
177 | } | 313 | } |
diff --git a/arch/x86/vdso/vdso32/vdso-fakesections.c b/arch/x86/vdso/vdso32/vdso-fakesections.c new file mode 100644 index 000000000000..541468e25265 --- /dev/null +++ b/arch/x86/vdso/vdso32/vdso-fakesections.c | |||
@@ -0,0 +1 @@ | |||
#include "../vdso-fakesections.c" | |||
diff --git a/arch/x86/vdso/vdsox32.lds.S b/arch/x86/vdso/vdsox32.lds.S index 46b991b578a8..697c11ece90c 100644 --- a/arch/x86/vdso/vdsox32.lds.S +++ b/arch/x86/vdso/vdsox32.lds.S | |||
@@ -6,6 +6,8 @@ | |||
6 | * the DSO. | 6 | * the DSO. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define BUILD_VDSOX32 | ||
10 | |||
9 | #include "vdso-layout.lds.S" | 11 | #include "vdso-layout.lds.S" |
10 | 12 | ||
11 | /* | 13 | /* |