aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/vdso
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-05-05 15:19:34 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2014-05-05 16:18:51 -0400
commit6f121e548f83674ab4920a4e60afb58d4f61b829 (patch)
tree699aa67f4e5242d1e3cd46513faf27493debc680 /arch/x86/vdso
parentcfda7bb9ecbf9d96264bb5bade33a842966d1062 (diff)
x86, vdso: Reimplement vdso.so preparation in build-time C
Currently, vdso.so files are prepared and analyzed by a combination of objcopy, nm, some linker script tricks, and some simple ELF parsers in the kernel. Replace all of that with plain C code that runs at build time. All five vdso images now generate .c files that are compiled and linked in to the kernel image. This should cause only one userspace-visible change: the loaded vDSO images are stripped more heavily than they used to be. Everything outside the loadable segment is dropped. In particular, this causes the section table and section name strings to be missing. This should be fine: real dynamic loaders don't load or inspect these tables anyway. The result is roughly equivalent to eu-strip's --strip-sections option. The purpose of this change is to enable the vvar and hpet mappings to be moved to the page following the vDSO load segment. Currently, it is possible for the section table to extend into the page after the load segment, so, if we map it, it risks overlapping the vvar or hpet page. This happens whenever the load segment is just under a multiple of PAGE_SIZE. The only real subtlety here is that the old code had a C file with inline assembler that did 'call VDSO32_vsyscall' and a linker script that defined 'VDSO32_vsyscall = __kernel_vsyscall'. This most likely worked by accident: the linker script entry defines a symbol associated with an address as opposed to an alias for the real dynamic symbol __kernel_vsyscall. That caused ld to relocate the reference at link time instead of leaving an interposable dynamic relocation. Since the VDSO32_vsyscall hack is no longer needed, I now use 'call __kernel_vsyscall', and I added -Bsymbolic to make it work. vdso2c will generate an error and abort the build if the resulting image contains any dynamic relocations, so we won't silently generate bad vdso images. (Dynamic relocations are a problem because nothing will even attempt to relocate the vdso.) Signed-off-by: Andy Lutomirski <luto@amacapital.net> Link: http://lkml.kernel.org/r/2c4fcf45524162a34d87fdda1eb046b2a5cecee7.1399317206.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/.gitignore5
-rw-r--r--arch/x86/vdso/Makefile90
-rw-r--r--arch/x86/vdso/vclock_gettime.c4
-rw-r--r--arch/x86/vdso/vdso.S3
-rw-r--r--arch/x86/vdso/vdso2c.c142
-rw-r--r--arch/x86/vdso/vdso2c.h137
-rw-r--r--arch/x86/vdso/vdso32-setup.c50
-rw-r--r--arch/x86/vdso/vdso32.S9
-rw-r--r--arch/x86/vdso/vdso32/vdso32.lds.S10
-rw-r--r--arch/x86/vdso/vdsox32.S3
-rw-r--r--arch/x86/vdso/vma.c100
11 files changed, 351 insertions, 202 deletions
diff --git a/arch/x86/vdso/.gitignore b/arch/x86/vdso/.gitignore
index 3282874bc61d..aae8ffdd5880 100644
--- a/arch/x86/vdso/.gitignore
+++ b/arch/x86/vdso/.gitignore
@@ -1,8 +1,7 @@
1vdso.lds 1vdso.lds
2vdso-syms.lds
3vdsox32.lds 2vdsox32.lds
4vdsox32-syms.lds
5vdso32-syms.lds
6vdso32-syscall-syms.lds 3vdso32-syscall-syms.lds
7vdso32-sysenter-syms.lds 4vdso32-sysenter-syms.lds
8vdso32-int80-syms.lds 5vdso32-int80-syms.lds
6vdso-image-*.c
7vdso2c
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index c580d1210ffe..895d4b16b7e3 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -24,15 +24,30 @@ vobj64s := $(filter-out $(vobjx32s-compat),$(vobjs-y))
24 24
25# files to link into kernel 25# files to link into kernel
26obj-y += vma.o 26obj-y += vma.o
27obj-$(VDSO64-y) += vdso.o 27
28obj-$(VDSOX32-y) += vdsox32.o 28# vDSO images to build
29obj-$(VDSO32-y) += vdso32.o vdso32-setup.o 29vdso_img-$(VDSO64-y) += 64
30vdso_img-$(VDSOX32-y) += x32
31vdso_img-$(VDSO32-y) += 32-int80
32vdso_img-$(CONFIG_COMPAT) += 32-syscall
33vdso_img-$(VDSO32-y) += 32-sysenter
34
35obj-$(VDSO32-y) += vdso32-setup.o
30 36
31vobjs := $(foreach F,$(vobj64s),$(obj)/$F) 37vobjs := $(foreach F,$(vobj64s),$(obj)/$F)
32 38
33$(obj)/vdso.o: $(obj)/vdso.so 39$(obj)/vdso.o: $(obj)/vdso.so
34 40
35targets += vdso.so vdso.so.dbg vdso.lds $(vobjs-y) 41targets += vdso.lds $(vobjs-y)
42
43# Build the vDSO image C files and link them in.
44vdso_img_objs := $(vdso_img-y:%=vdso-image-%.o)
45vdso_img_cfiles := $(vdso_img-y:%=vdso-image-%.c)
46vdso_img_sodbg := $(vdso_img-y:%=vdso%.so.dbg)
47obj-y += $(vdso_img_objs)
48targets += $(vdso_img_cfiles)
49targets += $(vdso_img_sodbg)
50.SECONDARY: $(vdso_img-y:%=$(obj)/vdso-image-%.c)
36 51
37export CPPFLAGS_vdso.lds += -P -C 52export CPPFLAGS_vdso.lds += -P -C
38 53
@@ -41,14 +56,18 @@ VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
41 -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \ 56 -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \
42 $(DISABLE_LTO) 57 $(DISABLE_LTO)
43 58
44$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so 59$(obj)/vdso64.so.dbg: $(src)/vdso.lds $(vobjs) FORCE
45
46$(obj)/vdso.so.dbg: $(src)/vdso.lds $(vobjs) FORCE
47 $(call if_changed,vdso) 60 $(call if_changed,vdso)
48 61
49$(obj)/%.so: OBJCOPYFLAGS := -S 62hostprogs-y += vdso2c
50$(obj)/%.so: $(obj)/%.so.dbg FORCE 63
51 $(call if_changed,objcopy) 64quiet_cmd_vdso2c = VDSO2C $@
65define cmd_vdso2c
66 $(obj)/vdso2c $< $@
67endef
68
69$(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso2c FORCE
70 $(call if_changed,vdso2c)
52 71
53# 72#
54# Don't omit frame pointers for ease of userspace debugging, but do 73# Don't omit frame pointers for ease of userspace debugging, but do
@@ -68,22 +87,6 @@ CFLAGS_REMOVE_vclock_gettime.o = -pg
68CFLAGS_REMOVE_vgetcpu.o = -pg 87CFLAGS_REMOVE_vgetcpu.o = -pg
69CFLAGS_REMOVE_vvar.o = -pg 88CFLAGS_REMOVE_vvar.o = -pg
70 89
71targets += vdso-syms.lds
72obj-$(VDSO64-y) += vdso-syms.lds
73
74#
75# Match symbols in the DSO that look like VDSO*; produce a file of constants.
76#
77sed-vdsosym := -e 's/^00*/0/' \
78 -e 's/^\([0-9a-fA-F]*\) . \(VDSO[a-zA-Z0-9_]*\)$$/\2 = 0x\1;/p'
79quiet_cmd_vdsosym = VDSOSYM $@
80define cmd_vdsosym
81 $(NM) $< | LC_ALL=C sed -n $(sed-vdsosym) | LC_ALL=C sort > $@
82endef
83
84$(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE
85 $(call if_changed,vdsosym)
86
87# 90#
88# X32 processes use x32 vDSO to access 64bit kernel data. 91# X32 processes use x32 vDSO to access 64bit kernel data.
89# 92#
@@ -94,9 +97,6 @@ $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE
94# so that it can reach 64bit address space with 64bit pointers. 97# so that it can reach 64bit address space with 64bit pointers.
95# 98#
96 99
97targets += vdsox32-syms.lds
98obj-$(VDSOX32-y) += vdsox32-syms.lds
99
100CPPFLAGS_vdsox32.lds = $(CPPFLAGS_vdso.lds) 100CPPFLAGS_vdsox32.lds = $(CPPFLAGS_vdso.lds)
101VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \ 101VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \
102 -Wl,-soname=linux-vdso.so.1 \ 102 -Wl,-soname=linux-vdso.so.1 \
@@ -113,9 +113,7 @@ quiet_cmd_x32 = X32 $@
113$(obj)/%-x32.o: $(obj)/%.o FORCE 113$(obj)/%-x32.o: $(obj)/%.o FORCE
114 $(call if_changed,x32) 114 $(call if_changed,x32)
115 115
116targets += vdsox32.so vdsox32.so.dbg vdsox32.lds $(vobjx32s-y) 116targets += vdsox32.lds $(vobjx32s-y)
117
118$(obj)/vdsox32.o: $(src)/vdsox32.S $(obj)/vdsox32.so
119 117
120$(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE 118$(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE
121 $(call if_changed,vdso) 119 $(call if_changed,vdso)
@@ -123,7 +121,6 @@ $(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE
123# 121#
124# Build multiple 32-bit vDSO images to choose from at boot time. 122# Build multiple 32-bit vDSO images to choose from at boot time.
125# 123#
126obj-$(VDSO32-y) += vdso32-syms.lds
127vdso32.so-$(VDSO32-y) += int80 124vdso32.so-$(VDSO32-y) += int80
128vdso32.so-$(CONFIG_COMPAT) += syscall 125vdso32.so-$(CONFIG_COMPAT) += syscall
129vdso32.so-$(VDSO32-y) += sysenter 126vdso32.so-$(VDSO32-y) += sysenter
@@ -138,10 +135,8 @@ VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1
138override obj-dirs = $(dir $(obj)) $(obj)/vdso32/ 135override obj-dirs = $(dir $(obj)) $(obj)/vdso32/
139 136
140targets += vdso32/vdso32.lds 137targets += vdso32/vdso32.lds
141targets += $(vdso32-images) $(vdso32-images:=.dbg)
142targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o) 138targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o)
143 139targets += vdso32/vclock_gettime.o
144extra-y += $(vdso32-images)
145 140
146$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%) 141$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%)
147 142
@@ -166,27 +161,6 @@ $(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
166 $(obj)/vdso32/%.o 161 $(obj)/vdso32/%.o
167 $(call if_changed,vdso) 162 $(call if_changed,vdso)
168 163
169# Make vdso32-*-syms.lds from each image, and then make sure they match.
170# The only difference should be that some do not define VDSO32_SYSENTER_RETURN.
171
172targets += vdso32-syms.lds $(vdso32.so-y:%=vdso32-%-syms.lds)
173
174quiet_cmd_vdso32sym = VDSOSYM $@
175define cmd_vdso32sym
176 if LC_ALL=C sort -u $(filter-out FORCE,$^) > $(@D)/.tmp_$(@F) && \
177 $(foreach H,$(filter-out FORCE,$^),\
178 if grep -q VDSO32_SYSENTER_RETURN $H; \
179 then diff -u $(@D)/.tmp_$(@F) $H; \
180 else sed /VDSO32_SYSENTER_RETURN/d $(@D)/.tmp_$(@F) | \
181 diff -u - $H; fi &&) : ;\
182 then mv -f $(@D)/.tmp_$(@F) $@; \
183 else rm -f $(@D)/.tmp_$(@F); exit 1; \
184 fi
185endef
186
187$(obj)/vdso32-syms.lds: $(vdso32.so-y:%=$(obj)/vdso32-%-syms.lds) FORCE
188 $(call if_changed,vdso32sym)
189
190# 164#
191# The DSO images are built using a special linker script. 165# The DSO images are built using a special linker script.
192# 166#
@@ -197,7 +171,7 @@ quiet_cmd_vdso = VDSO $@
197 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' 171 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
198 172
199VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \ 173VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
200 $(LTO_CFLAGS) 174 -Wl,-Bsymbolic $(LTO_CFLAGS)
201GCOV_PROFILE := n 175GCOV_PROFILE := n
202 176
203# 177#
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index 16d686171e9a..091554c20bc9 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -154,7 +154,7 @@ notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
154 asm( 154 asm(
155 "mov %%ebx, %%edx \n" 155 "mov %%ebx, %%edx \n"
156 "mov %2, %%ebx \n" 156 "mov %2, %%ebx \n"
157 "call VDSO32_vsyscall \n" 157 "call __kernel_vsyscall \n"
158 "mov %%edx, %%ebx \n" 158 "mov %%edx, %%ebx \n"
159 : "=a" (ret) 159 : "=a" (ret)
160 : "0" (__NR_clock_gettime), "g" (clock), "c" (ts) 160 : "0" (__NR_clock_gettime), "g" (clock), "c" (ts)
@@ -169,7 +169,7 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
169 asm( 169 asm(
170 "mov %%ebx, %%edx \n" 170 "mov %%ebx, %%edx \n"
171 "mov %2, %%ebx \n" 171 "mov %2, %%ebx \n"
172 "call VDSO32_vsyscall \n" 172 "call __kernel_vsyscall \n"
173 "mov %%edx, %%ebx \n" 173 "mov %%edx, %%ebx \n"
174 : "=a" (ret) 174 : "=a" (ret)
175 : "0" (__NR_gettimeofday), "g" (tv), "c" (tz) 175 : "0" (__NR_gettimeofday), "g" (tv), "c" (tz)
diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S
deleted file mode 100644
index be3f23b09af5..000000000000
--- a/arch/x86/vdso/vdso.S
+++ /dev/null
@@ -1,3 +0,0 @@
1#include <asm/vdso.h>
2
3DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so")
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c
new file mode 100644
index 000000000000..976e8e4ced92
--- /dev/null
+++ b/arch/x86/vdso/vdso2c.c
@@ -0,0 +1,142 @@
1#include <inttypes.h>
2#include <stdint.h>
3#include <unistd.h>
4#include <stdarg.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <fcntl.h>
9#include <err.h>
10
11#include <sys/mman.h>
12#include <sys/types.h>
13
14#include <linux/elf.h>
15#include <linux/types.h>
16
17/* Symbols that we need in vdso2c. */
18char const * const required_syms[] = {
19 "VDSO32_NOTE_MASK",
20 "VDSO32_SYSENTER_RETURN",
21 "__kernel_vsyscall",
22 "__kernel_sigreturn",
23 "__kernel_rt_sigreturn",
24};
25
26__attribute__((format(printf, 1, 2))) __attribute__((noreturn))
27static void fail(const char *format, ...)
28{
29 va_list ap;
30 va_start(ap, format);
31 fprintf(stderr, "Error: ");
32 vfprintf(stderr, format, ap);
33 exit(1);
34 va_end(ap);
35}
36
37#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))
38
39#define BITS 64
40#define GOFUNC go64
41#define Elf_Ehdr Elf64_Ehdr
42#define Elf_Shdr Elf64_Shdr
43#define Elf_Phdr Elf64_Phdr
44#define Elf_Sym Elf64_Sym
45#define Elf_Dyn Elf64_Dyn
46#include "vdso2c.h"
47#undef BITS
48#undef GOFUNC
49#undef Elf_Ehdr
50#undef Elf_Shdr
51#undef Elf_Phdr
52#undef Elf_Sym
53#undef Elf_Dyn
54
55#define BITS 32
56#define GOFUNC go32
57#define Elf_Ehdr Elf32_Ehdr
58#define Elf_Shdr Elf32_Shdr
59#define Elf_Phdr Elf32_Phdr
60#define Elf_Sym Elf32_Sym
61#define Elf_Dyn Elf32_Dyn
62#include "vdso2c.h"
63#undef BITS
64#undef GOFUNC
65#undef Elf_Ehdr
66#undef Elf_Shdr
67#undef Elf_Phdr
68#undef Elf_Sym
69#undef Elf_Dyn
70
71static int go(void *addr, size_t len, FILE *outfile, const char *name)
72{
73 Elf64_Ehdr *hdr = (Elf64_Ehdr *)addr;
74
75 if (hdr->e_ident[EI_CLASS] == ELFCLASS64) {
76 return go64(addr, len, outfile, name);
77 } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) {
78 return go32(addr, len, outfile, name);
79 } else {
80 fprintf(stderr, "Error: unknown ELF class\n");
81 return 1;
82 }
83}
84
85int main(int argc, char **argv)
86{
87 int fd;
88 off_t len;
89 void *addr;
90 FILE *outfile;
91 int ret;
92 char *name, *tmp;
93 int namelen;
94
95 if (argc != 3) {
96 printf("Usage: vdso2c INPUT OUTPUT\n");
97 return 1;
98 }
99
100 /*
101 * Figure out the struct name. If we're writing to a .so file,
102 * generate raw output insted.
103 */
104 name = strdup(argv[2]);
105 namelen = strlen(name);
106 if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) {
107 name = NULL;
108 } else {
109 tmp = strrchr(name, '/');
110 if (tmp)
111 name = tmp + 1;
112 tmp = strchr(name, '.');
113 if (tmp)
114 *tmp = '\0';
115 for (tmp = name; *tmp; tmp++)
116 if (*tmp == '-')
117 *tmp = '_';
118 }
119
120 fd = open(argv[1], O_RDONLY);
121 if (fd == -1)
122 err(1, "%s", argv[1]);
123
124 len = lseek(fd, 0, SEEK_END);
125 if (len == (off_t)-1)
126 err(1, "lseek");
127
128 addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
129 if (addr == MAP_FAILED)
130 err(1, "mmap");
131
132 outfile = fopen(argv[2], "w");
133 if (!outfile)
134 err(1, "%s", argv[2]);
135
136 ret = go(addr, (size_t)len, outfile, name);
137
138 munmap(addr, len);
139 fclose(outfile);
140
141 return ret;
142}
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
new file mode 100644
index 000000000000..9276e5207620
--- /dev/null
+++ b/arch/x86/vdso/vdso2c.h
@@ -0,0 +1,137 @@
1/*
2 * This file is included twice from vdso2c.c. It generates code for 32-bit
3 * and 64-bit vDSOs. We need both for 64-bit builds, since 32-bit vDSOs
4 * are built for 32-bit userspace.
5 */
6
7static int GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
8{
9 int found_load = 0;
10 unsigned long load_size = -1; /* Work around bogus warning */
11 unsigned long data_size;
12 Elf_Ehdr *hdr = (Elf_Ehdr *)addr;
13 int i;
14 unsigned long j;
15 Elf_Shdr *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr,
16 *alt_sec = NULL;
17 Elf_Dyn *dyn = 0, *dyn_end = 0;
18 const char *secstrings;
19 uint64_t syms[NSYMS] = {};
20
21 Elf_Phdr *pt = (Elf_Phdr *)(addr + hdr->e_phoff);
22
23 /* Walk the segment table. */
24 for (i = 0; i < hdr->e_phnum; i++) {
25 if (pt[i].p_type == PT_LOAD) {
26 if (found_load)
27 fail("multiple PT_LOAD segs\n");
28
29 if (pt[i].p_offset != 0 || pt[i].p_vaddr != 0)
30 fail("PT_LOAD in wrong place\n");
31
32 if (pt[i].p_memsz != pt[i].p_filesz)
33 fail("cannot handle memsz != filesz\n");
34
35 load_size = pt[i].p_memsz;
36 found_load = 1;
37 } else if (pt[i].p_type == PT_DYNAMIC) {
38 dyn = addr + pt[i].p_offset;
39 dyn_end = addr + pt[i].p_offset + pt[i].p_memsz;
40 }
41 }
42 if (!found_load)
43 fail("no PT_LOAD seg\n");
44 data_size = (load_size + 4095) / 4096 * 4096;
45
46 /* Walk the dynamic table */
47 for (i = 0; dyn + i < dyn_end && dyn[i].d_tag != DT_NULL; i++) {
48 if (dyn[i].d_tag == DT_REL || dyn[i].d_tag == DT_RELSZ ||
49 dyn[i].d_tag == DT_RELENT || dyn[i].d_tag == DT_TEXTREL)
50 fail("vdso image contains dynamic relocations\n");
51 }
52
53 /* Walk the section table */
54 secstrings_hdr = addr + hdr->e_shoff + hdr->e_shentsize*hdr->e_shstrndx;
55 secstrings = addr + secstrings_hdr->sh_offset;
56 for (i = 0; i < hdr->e_shnum; i++) {
57 Elf_Shdr *sh = addr + hdr->e_shoff + hdr->e_shentsize * i;
58 if (sh->sh_type == SHT_SYMTAB)
59 symtab_hdr = sh;
60
61 if (!strcmp(secstrings + sh->sh_name, ".altinstructions"))
62 alt_sec = sh;
63 }
64
65 if (!symtab_hdr) {
66 fail("no symbol table\n");
67 return 1;
68 }
69
70 strtab_hdr = addr + hdr->e_shoff +
71 hdr->e_shentsize * symtab_hdr->sh_link;
72
73 /* Walk the symbol table */
74 for (i = 0; i < symtab_hdr->sh_size / symtab_hdr->sh_entsize; i++) {
75 int k;
76 Elf_Sym *sym = addr + symtab_hdr->sh_offset +
77 symtab_hdr->sh_entsize * i;
78 const char *name = addr + strtab_hdr->sh_offset + sym->st_name;
79 for (k = 0; k < NSYMS; k++) {
80 if (!strcmp(name, required_syms[k])) {
81 if (syms[k]) {
82 fail("duplicate symbol %s\n",
83 required_syms[k]);
84 }
85 syms[k] = sym->st_value;
86 }
87 }
88 }
89
90 /* Remove sections. */
91 hdr->e_shoff = 0;
92 hdr->e_shentsize = 0;
93 hdr->e_shnum = 0;
94 hdr->e_shstrndx = SHN_UNDEF;
95
96 if (!name) {
97 fwrite(addr, load_size, 1, outfile);
98 return 0;
99 }
100
101 fprintf(outfile, "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n\n");
102 fprintf(outfile, "#include <linux/linkage.h>\n");
103 fprintf(outfile, "#include <asm/page_types.h>\n");
104 fprintf(outfile, "#include <asm/vdso.h>\n");
105 fprintf(outfile, "\n");
106 fprintf(outfile,
107 "static unsigned char raw_data[%lu] __page_aligned_data = {",
108 data_size);
109 for (j = 0; j < load_size; j++) {
110 if (j % 10 == 0)
111 fprintf(outfile, "\n\t");
112 fprintf(outfile, "0x%02X, ", (int)((unsigned char *)addr)[j]);
113 }
114 fprintf(outfile, "\n};\n\n");
115
116 fprintf(outfile, "static struct page *pages[%lu];\n\n",
117 data_size / 4096);
118
119 fprintf(outfile, "const struct vdso_image %s = {\n", name);
120 fprintf(outfile, "\t.data = raw_data,\n");
121 fprintf(outfile, "\t.size = %lu,\n", data_size);
122 fprintf(outfile, "\t.pages = pages,\n");
123 if (alt_sec) {
124 fprintf(outfile, "\t.alt = %lu,\n",
125 (unsigned long)alt_sec->sh_offset);
126 fprintf(outfile, "\t.alt_len = %lu,\n",
127 (unsigned long)alt_sec->sh_size);
128 }
129 for (i = 0; i < NSYMS; i++) {
130 if (syms[i])
131 fprintf(outfile, "\t.sym_%s = 0x%" PRIx64 ",\n",
132 required_syms[i], syms[i]);
133 }
134 fprintf(outfile, "};\n");
135
136 return 0;
137}
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 9c78d5b24874..d41460118a28 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -29,6 +29,7 @@
29#include <asm/fixmap.h> 29#include <asm/fixmap.h>
30#include <asm/hpet.h> 30#include <asm/hpet.h>
31#include <asm/vvar.h> 31#include <asm/vvar.h>
32#include <asm/vdso32.h>
32 33
33#ifdef CONFIG_COMPAT_VDSO 34#ifdef CONFIG_COMPAT_VDSO
34#define VDSO_DEFAULT 0 35#define VDSO_DEFAULT 0
@@ -67,9 +68,6 @@ __setup("vdso32=", vdso32_setup);
67__setup_param("vdso=", vdso_setup, vdso32_setup, 0); 68__setup_param("vdso=", vdso_setup, vdso32_setup, 0);
68#endif 69#endif
69 70
70static struct page **vdso32_pages;
71static unsigned vdso32_size;
72
73#ifdef CONFIG_X86_64 71#ifdef CONFIG_X86_64
74 72
75#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32)) 73#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32))
@@ -82,34 +80,23 @@ static unsigned vdso32_size;
82 80
83#endif /* CONFIG_X86_64 */ 81#endif /* CONFIG_X86_64 */
84 82
83#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT)
84const struct vdso_image *selected_vdso32;
85#endif
86
85int __init sysenter_setup(void) 87int __init sysenter_setup(void)
86{ 88{
87 char *vdso32_start, *vdso32_end;
88 int npages, i;
89
90#ifdef CONFIG_COMPAT 89#ifdef CONFIG_COMPAT
91 if (vdso32_syscall()) { 90 if (vdso32_syscall())
92 vdso32_start = vdso32_syscall_start; 91 selected_vdso32 = &vdso_image_32_syscall;
93 vdso32_end = vdso32_syscall_end; 92 else
94 vdso32_pages = vdso32_syscall_pages;
95 } else
96#endif 93#endif
97 if (vdso32_sysenter()) { 94 if (vdso32_sysenter())
98 vdso32_start = vdso32_sysenter_start; 95 selected_vdso32 = &vdso_image_32_sysenter;
99 vdso32_end = vdso32_sysenter_end; 96 else
100 vdso32_pages = vdso32_sysenter_pages; 97 selected_vdso32 = &vdso_image_32_int80;
101 } else {
102 vdso32_start = vdso32_int80_start;
103 vdso32_end = vdso32_int80_end;
104 vdso32_pages = vdso32_int80_pages;
105 }
106
107 npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE;
108 vdso32_size = npages << PAGE_SHIFT;
109 for (i = 0; i < npages; i++)
110 vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE);
111 98
112 patch_vdso32(vdso32_start, vdso32_size); 99 init_vdso_image(selected_vdso32);
113 100
114 return 0; 101 return 0;
115} 102}
@@ -121,6 +108,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
121 unsigned long addr; 108 unsigned long addr;
122 int ret = 0; 109 int ret = 0;
123 struct vm_area_struct *vma; 110 struct vm_area_struct *vma;
111 unsigned long vdso32_size = selected_vdso32->size;
124 112
125#ifdef CONFIG_X86_X32_ABI 113#ifdef CONFIG_X86_X32_ABI
126 if (test_thread_flag(TIF_X32)) 114 if (test_thread_flag(TIF_X32))
@@ -140,7 +128,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
140 128
141 addr += VDSO_OFFSET(VDSO_PREV_PAGES); 129 addr += VDSO_OFFSET(VDSO_PREV_PAGES);
142 130
143 current->mm->context.vdso = (void *)addr; 131 current->mm->context.vdso = (void __user *)addr;
144 132
145 /* 133 /*
146 * MAYWRITE to allow gdb to COW and set breakpoints 134 * MAYWRITE to allow gdb to COW and set breakpoints
@@ -150,7 +138,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
150 vdso32_size, 138 vdso32_size,
151 VM_READ|VM_EXEC| 139 VM_READ|VM_EXEC|
152 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 140 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
153 vdso32_pages); 141 selected_vdso32->pages);
154 142
155 if (ret) 143 if (ret)
156 goto up_fail; 144 goto up_fail;
@@ -188,8 +176,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
188 } 176 }
189#endif 177#endif
190 178
191 current_thread_info()->sysenter_return = 179 if (selected_vdso32->sym_VDSO32_SYSENTER_RETURN)
192 VDSO32_SYMBOL(addr, SYSENTER_RETURN); 180 current_thread_info()->sysenter_return =
181 current->mm->context.vdso +
182 selected_vdso32->sym_VDSO32_SYSENTER_RETURN;
193 183
194 up_fail: 184 up_fail:
195 if (ret) 185 if (ret)
diff --git a/arch/x86/vdso/vdso32.S b/arch/x86/vdso/vdso32.S
deleted file mode 100644
index 018bcd9f97b4..000000000000
--- a/arch/x86/vdso/vdso32.S
+++ /dev/null
@@ -1,9 +0,0 @@
1#include <asm/vdso.h>
2
3DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so")
4
5#ifdef CONFIG_COMPAT
6DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so")
7#endif
8
9DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so")
diff --git a/arch/x86/vdso/vdso32/vdso32.lds.S b/arch/x86/vdso/vdso32/vdso32.lds.S
index aadb8b9994cd..f072095d6427 100644
--- a/arch/x86/vdso/vdso32/vdso32.lds.S
+++ b/arch/x86/vdso/vdso32/vdso32.lds.S
@@ -38,13 +38,3 @@ VERSION
38 local: *; 38 local: *;
39 }; 39 };
40} 40}
41
42/*
43 * Symbols we define here called VDSO* get their values into vdso32-syms.h.
44 */
45VDSO32_vsyscall = __kernel_vsyscall;
46VDSO32_sigreturn = __kernel_sigreturn;
47VDSO32_rt_sigreturn = __kernel_rt_sigreturn;
48VDSO32_clock_gettime = clock_gettime;
49VDSO32_gettimeofday = gettimeofday;
50VDSO32_time = time;
diff --git a/arch/x86/vdso/vdsox32.S b/arch/x86/vdso/vdsox32.S
deleted file mode 100644
index f4aa34e7f370..000000000000
--- a/arch/x86/vdso/vdsox32.S
+++ /dev/null
@@ -1,3 +0,0 @@
1#include <asm/vdso.h>
2
3DEFINE_VDSO_IMAGE(vdsox32, "arch/x86/vdso/vdsox32.so")
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 8b790398ed1d..cf217626fb47 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -19,99 +19,31 @@
19#if defined(CONFIG_X86_64) 19#if defined(CONFIG_X86_64)
20unsigned int __read_mostly vdso64_enabled = 1; 20unsigned int __read_mostly vdso64_enabled = 1;
21 21
22DECLARE_VDSO_IMAGE(vdso);
23extern unsigned short vdso_sync_cpuid; 22extern unsigned short vdso_sync_cpuid;
24static unsigned vdso_size;
25
26#ifdef CONFIG_X86_X32_ABI
27DECLARE_VDSO_IMAGE(vdsox32);
28static unsigned vdsox32_size;
29#endif
30#endif 23#endif
31 24
32#if defined(CONFIG_X86_32) || defined(CONFIG_X86_X32_ABI) || \ 25void __init init_vdso_image(const struct vdso_image *image)
33 defined(CONFIG_COMPAT)
34void __init patch_vdso32(void *vdso, size_t len)
35{ 26{
36 Elf32_Ehdr *hdr = vdso;
37 Elf32_Shdr *sechdrs, *alt_sec = 0;
38 char *secstrings;
39 void *alt_data;
40 int i; 27 int i;
28 int npages = (image->size) / PAGE_SIZE;
41 29
42 BUG_ON(len < sizeof(Elf32_Ehdr)); 30 BUG_ON(image->size % PAGE_SIZE != 0);
43 BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0); 31 for (i = 0; i < npages; i++)
44 32 image->pages[i] = virt_to_page(image->data + i*PAGE_SIZE);
45 sechdrs = (void *)hdr + hdr->e_shoff;
46 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
47
48 for (i = 1; i < hdr->e_shnum; i++) {
49 Elf32_Shdr *shdr = &sechdrs[i];
50 if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) {
51 alt_sec = shdr;
52 goto found;
53 }
54 }
55
56 /* If we get here, it's probably a bug. */
57 pr_warning("patch_vdso32: .altinstructions not found\n");
58 return; /* nothing to patch */
59 33
60found: 34 apply_alternatives((struct alt_instr *)(image->data + image->alt),
61 alt_data = (void *)hdr + alt_sec->sh_offset; 35 (struct alt_instr *)(image->data + image->alt +
62 apply_alternatives(alt_data, alt_data + alt_sec->sh_size); 36 image->alt_len));
63} 37}
64#endif
65
66#if defined(CONFIG_X86_64)
67static void __init patch_vdso64(void *vdso, size_t len)
68{
69 Elf64_Ehdr *hdr = vdso;
70 Elf64_Shdr *sechdrs, *alt_sec = 0;
71 char *secstrings;
72 void *alt_data;
73 int i;
74 38
75 BUG_ON(len < sizeof(Elf64_Ehdr));
76 BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0);
77
78 sechdrs = (void *)hdr + hdr->e_shoff;
79 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
80
81 for (i = 1; i < hdr->e_shnum; i++) {
82 Elf64_Shdr *shdr = &sechdrs[i];
83 if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) {
84 alt_sec = shdr;
85 goto found;
86 }
87 }
88
89 /* If we get here, it's probably a bug. */
90 pr_warning("patch_vdso64: .altinstructions not found\n");
91 return; /* nothing to patch */
92
93found:
94 alt_data = (void *)hdr + alt_sec->sh_offset;
95 apply_alternatives(alt_data, alt_data + alt_sec->sh_size);
96}
97 39
40#if defined(CONFIG_X86_64)
98static int __init init_vdso(void) 41static int __init init_vdso(void)
99{ 42{
100 int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE; 43 init_vdso_image(&vdso_image_64);
101 int i;
102
103 patch_vdso64(vdso_start, vdso_end - vdso_start);
104
105 vdso_size = npages << PAGE_SHIFT;
106 for (i = 0; i < npages; i++)
107 vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE);
108 44
109#ifdef CONFIG_X86_X32_ABI 45#ifdef CONFIG_X86_X32_ABI
110 patch_vdso32(vdsox32_start, vdsox32_end - vdsox32_start); 46 init_vdso_image(&vdso_image_x32);
111 npages = (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE;
112 vdsox32_size = npages << PAGE_SHIFT;
113 for (i = 0; i < npages; i++)
114 vdsox32_pages[i] = virt_to_page(vdsox32_start + i*PAGE_SIZE);
115#endif 47#endif
116 48
117 return 0; 49 return 0;
@@ -171,7 +103,7 @@ static int setup_additional_pages(struct linux_binprm *bprm,
171 goto up_fail; 103 goto up_fail;
172 } 104 }
173 105
174 current->mm->context.vdso = (void *)addr; 106 current->mm->context.vdso = (void __user *)addr;
175 107
176 ret = install_special_mapping(mm, addr, size, 108 ret = install_special_mapping(mm, addr, size,
177 VM_READ|VM_EXEC| 109 VM_READ|VM_EXEC|
@@ -189,15 +121,15 @@ up_fail:
189 121
190int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 122int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
191{ 123{
192 return setup_additional_pages(bprm, uses_interp, vdso_pages, 124 return setup_additional_pages(bprm, uses_interp, vdso_image_64.pages,
193 vdso_size); 125 vdso_image_64.size);
194} 126}
195 127
196#ifdef CONFIG_X86_X32_ABI 128#ifdef CONFIG_X86_X32_ABI
197int x32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 129int x32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
198{ 130{
199 return setup_additional_pages(bprm, uses_interp, vdsox32_pages, 131 return setup_additional_pages(bprm, uses_interp, vdso_image_x32.pages,
200 vdsox32_size); 132 vdso_image_x32.size);
201} 133}
202#endif 134#endif
203 135