Skip to content

Commit da861e1

Browse files
amlutoH. Peter Anvin
authored andcommitted
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>
1 parent e6577a7 commit da861e1

File tree

4 files changed

+126
-229
lines changed

4 files changed

+126
-229
lines changed

arch/x86/vdso/Makefile

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ VDSO32-$(CONFIG_X86_32) := y
1010
VDSO32-$(CONFIG_COMPAT) := y
1111

1212
# 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
1414

1515
# files to link into kernel
1616
obj-y += vma.o
@@ -37,7 +37,8 @@ vdso_img_sodbg := $(vdso_img-y:%=vdso%.so.dbg)
3737
obj-y += $(vdso_img_objs)
3838
targets += $(vdso_img_cfiles)
3939
targets += $(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)
4142

4243
export CPPFLAGS_vdso.lds += -P -C
4344

@@ -54,10 +55,10 @@ hostprogs-y += vdso2c
5455

5556
quiet_cmd_vdso2c = VDSO2C $@
5657
define cmd_vdso2c
57-
$(obj)/vdso2c $< $@
58+
$(obj)/vdso2c $< $(<:%.dbg=%) $@
5859
endef
5960

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
6162
$(call if_changed,vdso2c)
6263

6364
#
@@ -113,6 +114,10 @@ $(obj)/%-x32.o: $(obj)/%.o FORCE
113114

114115
targets += vdsox32.lds $(vobjx32s-y)
115116

117+
$(obj)/%.so: OBJCOPYFLAGS := -S
118+
$(obj)/%.so: $(obj)/%.so.dbg
119+
$(call if_changed,objcopy)
120+
116121
$(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE
117122
$(call if_changed,vdso)
118123

@@ -134,7 +139,7 @@ override obj-dirs = $(dir $(obj)) $(obj)/vdso32/
134139

135140
targets += vdso32/vdso32.lds
136141
targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o)
137-
targets += vdso32/vclock_gettime.o vdso32/vdso-fakesections.o
142+
targets += vdso32/vclock_gettime.o
138143

139144
$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%)
140145

@@ -156,7 +161,6 @@ $(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
156161
$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
157162
$(obj)/vdso32/vdso32.lds \
158163
$(obj)/vdso32/vclock_gettime.o \
159-
$(obj)/vdso32/vdso-fakesections.o \
160164
$(obj)/vdso32/note.o \
161165
$(obj)/vdso32/%.o
162166
$(call if_changed,vdso)

arch/x86/vdso/vdso-fakesections.c

Lines changed: 0 additions & 21 deletions
This file was deleted.

arch/x86/vdso/vdso2c.c

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
151
#include <inttypes.h>
252
#include <stdint.h>
353
#include <unistd.h>
@@ -61,7 +111,8 @@ static void fail(const char *format, ...)
61111
va_start(ap, format);
62112
fprintf(stderr, "Error: ");
63113
vfprintf(stderr, format, ap);
64-
unlink(outfilename);
114+
if (outfilename)
115+
unlink(outfilename);
65116
exit(1);
66117
va_end(ap);
67118
}
@@ -114,38 +165,61 @@ extern void bad_put_le(void);
114165
#include "vdso2c.h"
115166
#undef ELF_BITS
116167

117-
static void go(void *addr, size_t len, FILE *outfile, const char *name)
168+
static void go(void *raw_addr, size_t raw_len,
169+
void *stripped_addr, size_t stripped_len,
170+
FILE *outfile, const char *name)
118171
{
119-
Elf64_Ehdr *hdr = (Elf64_Ehdr *)addr;
172+
Elf64_Ehdr *hdr = (Elf64_Ehdr *)raw_addr;
120173

121174
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);
123177
} 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);
125180
} else {
126181
fail("unknown ELF class\n");
127182
}
128183
}
129184

185+
static 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+
130205
int main(int argc, char **argv)
131206
{
132-
int fd;
133-
off_t len;
134-
void *addr;
207+
size_t raw_len, stripped_len;
208+
void *raw_addr, *stripped_addr;
135209
FILE *outfile;
136210
char *name, *tmp;
137211
int namelen;
138212

139-
if (argc != 3) {
140-
printf("Usage: vdso2c INPUT OUTPUT\n");
213+
if (argc != 4) {
214+
printf("Usage: vdso2c RAW_INPUT STRIPPED_INPUT OUTPUT\n");
141215
return 1;
142216
}
143217

144218
/*
145219
* Figure out the struct name. If we're writing to a .so file,
146220
* generate raw output insted.
147221
*/
148-
name = strdup(argv[2]);
222+
name = strdup(argv[3]);
149223
namelen = strlen(name);
150224
if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) {
151225
name = NULL;
@@ -161,26 +235,18 @@ int main(int argc, char **argv)
161235
*tmp = '_';
162236
}
163237

164-
fd = open(argv[1], O_RDONLY);
165-
if (fd == -1)
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");
238+
map_input(argv[1], &raw_addr, &raw_len, PROT_READ);
239+
map_input(argv[2], &stripped_addr, &stripped_len, PROT_READ);
175240

176-
outfilename = argv[2];
241+
outfilename = argv[3];
177242
outfile = fopen(outfilename, "w");
178243
if (!outfile)
179244
err(1, "%s", argv[2]);
180245

181-
go(addr, (size_t)len, outfile, name);
246+
go(raw_addr, raw_len, stripped_addr, stripped_len, outfile, name);
182247

183-
munmap(addr, len);
248+
munmap(raw_addr, raw_len);
249+
munmap(stripped_addr, stripped_len);
184250
fclose(outfile);
185251

186252
return 0;

0 commit comments

Comments
 (0)