diff options
| -rw-r--r-- | arch/x86/include/asm/vdso.h | 18 | ||||
| -rw-r--r-- | arch/x86/vdso/vdso-layout.lds.S | 44 | ||||
| -rw-r--r-- | arch/x86/vdso/vdso2c.c | 12 | ||||
| -rw-r--r-- | arch/x86/vdso/vdso2c.h | 25 | ||||
| -rw-r--r-- | arch/x86/vdso/vma.c | 20 |
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 | ||
| 19 | SECTIONS | 19 | SECTIONS |
| 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. */ |
| 22 | enum { | 22 | enum { |
| 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 | ||
| 40 | struct vdso_sym required_syms[] = { | 40 | struct 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 | } | 279 | } |
| 273 | if (syms[sym_end_mapping] % 4096) | 280 | if (syms[sym_vvar_start] % 4096) |
| 274 | fail("end_mapping must be a multiple of 4096\n"); | 281 | fail("vvar_begin must be a multiple of 4096\n"); |
| 275 | 282 | ||
| 276 | if (!name) { | ||
