aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-07-10 21:13:15 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2014-07-11 19:57:51 -0400
commite6577a7ce99a506b587bcd1d2cd803cb45119557 (patch)
tree71e985803dce2a087d98f98537efd37d1ba630e3
parentd093601be5e97d2729614419d0d256ed3b6a56b0 (diff)
x86, vdso: Move the vvar area before the vdso text
Putting the vvar area after the vdso text is rather complicated: it only works of the total length of the vdso text mapping is known at vdso link time, and the linker doesn't allow symbol addresses to depend on the sizes of non-allocatable data after the PT_LOAD segment. Moving the vvar area before the vdso text will allow is to safely map non-allocatable data after the vdso text, which is a nice simplification. Signed-off-by: Andy Lutomirski <luto@amacapital.net> Link: http://lkml.kernel.org/r/156c78c0d93144ff1055a66493783b9e56813983.1405040914.git.luto@amacapital.net Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--arch/x86/include/asm/vdso.h18
-rw-r--r--arch/x86/vdso/vdso-layout.lds.S44
-rw-r--r--arch/x86/vdso/vdso2c.c12
-rw-r--r--arch/x86/vdso/vdso2c.h25
-rw-r--r--arch/x86/vdso/vma.c20
5 files changed, 62 insertions, 57 deletions
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index 30be253dd283..8021bd28c0f1 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -18,15 +18,15 @@ struct vdso_image {
18 18
19 unsigned long alt, alt_len; 19 unsigned long alt, alt_len;
20 20
21 unsigned long sym_end_mapping; /* Total size of the mapping */ 21 long sym_vvar_start; /* Negative offset to the vvar area */
22 22
23 unsigned long sym_vvar_page; 23 long sym_vvar_page;
24 unsigned long sym_hpet_page; 24 long sym_hpet_page;
25 unsigned long sym_VDSO32_NOTE_MASK; 25 long sym_VDSO32_NOTE_MASK;
26 unsigned long sym___kernel_sigreturn; 26 long sym___kernel_sigreturn;
27 unsigned long sym___kernel_rt_sigreturn; 27 long sym___kernel_rt_sigreturn;
28 unsigned long sym___kernel_vsyscall; 28 long sym___kernel_vsyscall;
29 unsigned long sym_VDSO32_SYSENTER_RETURN; 29 long sym_VDSO32_SYSENTER_RETURN;
30}; 30};
31 31
32#ifdef CONFIG_X86_64 32#ifdef CONFIG_X86_64
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S
index 9197544eea9a..de2c921025f5 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/vdso/vdso-layout.lds.S
@@ -18,6 +18,25 @@
18 18
19SECTIONS 19SECTIONS
20{ 20{
21 /*
22 * User/kernel shared data is before the vDSO. This may be a little
23 * uglier than putting it after the vDSO, but it avoids issues with
24 * non-allocatable things that dangle past the end of the PT_LOAD
25 * segment.
26 */
27
28 vvar_start = . - 2 * PAGE_SIZE;
29 vvar_page = vvar_start;
30
31 /* Place all vvars at the offsets in asm/vvar.h. */
32#define EMIT_VVAR(name, offset) vvar_ ## name = vvar_page + offset;
33#define __VVAR_KERNEL_LDS
34#include <asm/vvar.h>
35#undef __VVAR_KERNEL_LDS
36#undef EMIT_VVAR
37
38 hpet_page = vvar_start + PAGE_SIZE;
39
21 . = SIZEOF_HEADERS; 40 . = SIZEOF_HEADERS;
22 41
23 .hash : { *(.hash) } :text 42 .hash : { *(.hash) } :text
@@ -74,31 +93,6 @@ SECTIONS
74 .altinstructions : { *(.altinstructions) } :text 93 .altinstructions : { *(.altinstructions) } :text
75 .altinstr_replacement : { *(.altinstr_replacement) } :text 94 .altinstr_replacement : { *(.altinstr_replacement) } :text
76 95
77 /*
78 * The remainder of the vDSO consists of special pages that are
79 * shared between the kernel and userspace. It needs to be at the
80 * end so that it doesn't overlap the mapping of the actual
81 * vDSO image.
82 */
83
84 . = ALIGN(PAGE_SIZE);
85 vvar_page = .;
86
87 /* Place all vvars at the offsets in asm/vvar.h. */
88#define EMIT_VVAR(name, offset) vvar_ ## name = vvar_page + offset;
89#define __VVAR_KERNEL_LDS
90#include <asm/vvar.h>
91#undef __VVAR_KERNEL_LDS
92#undef EMIT_VVAR
93
94 . = vvar_page + PAGE_SIZE;
95
96 hpet_page = .;
97 . = . + PAGE_SIZE;
98
99 . = ALIGN(PAGE_SIZE);
100 end_mapping = .;
101
102 /DISCARD/ : { 96 /DISCARD/ : {
103 *(.discard) 97 *(.discard)
104 *(.discard.*) 98 *(.discard.*)
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c
index 238dbe82776e..22c54d04bced 100644
--- a/arch/x86/vdso/vdso2c.c
+++ b/arch/x86/vdso/vdso2c.c
@@ -20,9 +20,9 @@ const char *outfilename;
20 20
21/* Symbols that we need in vdso2c. */ 21/* Symbols that we need in vdso2c. */
22enum { 22enum {
23 sym_vvar_start,
23 sym_vvar_page, 24 sym_vvar_page,
24 sym_hpet_page, 25 sym_hpet_page,
25 sym_end_mapping,
26 sym_VDSO_FAKE_SECTION_TABLE_START, 26 sym_VDSO_FAKE_SECTION_TABLE_START,
27 sym_VDSO_FAKE_SECTION_TABLE_END, 27 sym_VDSO_FAKE_SECTION_TABLE_END,
28}; 28};
@@ -38,9 +38,9 @@ struct vdso_sym {
38}; 38};
39 39
40struct vdso_sym required_syms[] = { 40struct vdso_sym required_syms[] = {
41 [sym_vvar_start] = {"vvar_start", true},
41 [sym_vvar_page] = {"vvar_page", true}, 42 [sym_vvar_page] = {"vvar_page", true},
42 [sym_hpet_page] = {"hpet_page", true}, 43 [sym_hpet_page] = {"hpet_page", true},
43 [sym_end_mapping] = {"end_mapping", true},
44 [sym_VDSO_FAKE_SECTION_TABLE_START] = { 44 [sym_VDSO_FAKE_SECTION_TABLE_START] = {
45 "VDSO_FAKE_SECTION_TABLE_START", false 45 "VDSO_FAKE_SECTION_TABLE_START", false
46 }, 46 },
@@ -96,9 +96,11 @@ extern void bad_put_le(void);
96 96
97#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0])) 97#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))
98 98
99#define BITSFUNC3(name, bits) name##bits 99#define BITSFUNC3(name, bits, suffix) name##bits##suffix
100#define BITSFUNC2(name, bits) BITSFUNC3(name, bits) 100#define BITSFUNC2(name, bits, suffix) BITSFUNC3(name, bits, suffix)
101#define BITSFUNC(name) BITSFUNC2(name, ELF_BITS) 101#define BITSFUNC(name) BITSFUNC2(name, ELF_BITS, )
102
103#define INT_BITS BITSFUNC2(int, ELF_BITS, _t)
102 104
103#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x 105#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
104#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x) 106#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
index 11b65d4f9414..2da32fbc46da 100644
--- a/arch/x86/vdso/vdso2c.h
+++ b/arch/x86/vdso/vdso2c.h
@@ -132,7 +132,7 @@ static void BITSFUNC(go)(void *addr, size_t len,
132 *alt_sec = NULL; 132 *alt_sec = NULL;
133 ELF(Dyn) *dyn = 0, *dyn_end = 0; 133 ELF(Dyn) *dyn = 0, *dyn_end = 0;
134 const char *secstrings; 134 const char *secstrings;
135 uint64_t syms[NSYMS] = {}; 135 INT_BITS syms[NSYMS] = {};
136 136
137 struct BITSFUNC(fake_sections) fake_sections = {}; 137 struct BITSFUNC(fake_sections) fake_sections = {};
138 138
@@ -209,6 +209,13 @@ static void BITSFUNC(go)(void *addr, size_t len,
209 fail("duplicate symbol %s\n", 209 fail("duplicate symbol %s\n",
210 required_syms[k].name); 210 required_syms[k].name);
211 } 211 }
212
213 /*
214 * Careful: we use negative addresses, but
215 * st_value is unsigned, so we rely
216 * on syms[k] being a signed type of the
217 * correct width.
218 */
212 syms[k] = GET_LE(&sym->st_value); 219 syms[k] = GET_LE(&sym->st_value);
213 } 220 }
214 } 221 }
@@ -263,15 +270,15 @@ static void BITSFUNC(go)(void *addr, size_t len,
263 if (syms[i] % 4096) 270 if (syms[i] % 4096)
264 fail("%s must be a multiple of 4096\n", 271 fail("%s must be a multiple of 4096\n",
265 required_syms[i].name); 272 required_syms[i].name);
266 if (syms[i] < data_size) 273 if (syms[sym_vvar_start] > syms[i] + 4096)
267 fail("%s must be after the text mapping\n", 274 fail("%s underruns begin_vvar\n",
268 required_syms[i].name); 275 required_syms[i].name);
269 if (syms[sym_end_mapping] < syms[i] + 4096) 276 if (syms[i] + 4096 > 0)
270 fail("%s overruns end_mapping\n", 277 fail("%s is on the wrong side of the vdso text\n",
271 required_syms[i].name); 278 required_syms[i].name);
272 }