This series makes me sad. It brings the 64-bit vdso back above 4kB,
like it was in 3.15. It's also just silly, but it seems to be
needed to keep binutils happy when debugging the vdso.
Patch 5 isn't really necessary, and is likely not 3.16 material.
It's useful for testing the rest of this series, though.
Only patch 5 changed from v1:
- Fix for old binutils.
- Pass --build-id, since normal binutils may not have it on by default.
Andy Lutomirski (5):
x86,vdso: Discard the __bug_table section
x86,vdso2c: Use better macros for ELF bitness
x86,vdso: Improve the fake section headers
x86,vdso: Remove some redundant in-memory section headers
x86,vdso: Create .build-id links for unstripped vdso files
arch/x86/vdso/Makefile | 20 +++-
arch/x86/vdso/vdso-fakesections.c | 41 +++----
arch/x86/vdso/vdso-layout.lds.S | 64 +++++++---
arch/x86/vdso/vdso.lds.S | 2 +
arch/x86/vdso/vdso2c.c | 73 ++++++------
arch/x86/vdso/vdso2c.h | 197 ++++++++++++++++++++++++++-----
arch/x86/vdso/vdso32/vdso-fakesections.c | 1 +
arch/x86/vdso/vdsox32.lds.S | 2 +
8 files changed, 284 insertions(+), 116 deletions(-)
create mode 100644 arch/x86/vdso/vdso32/vdso-fakesections.c
--
1.9.3
It serves no purpose in user code.
Signed-off-by: Andy Lutomirski <[email protected]>
---
arch/x86/vdso/vdso-layout.lds.S | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S
index 2ec72f6..c84166c 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/vdso/vdso-layout.lds.S
@@ -75,6 +75,7 @@ SECTIONS
/DISCARD/ : {
*(.discard)
*(.discard.*)
+ *(__bug_table)
}
}
--
1.9.3
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 <[email protected]>
---
arch/x86/vdso/Makefile | 4 +-
arch/x86/vdso/vdso-fakesections.c | 44 ++++----
arch/x86/vdso/vdso-layout.lds.S | 40 +++++--
arch/x86/vdso/vdso.lds.S | 2 +
arch/x86/vdso/vdso2c.c | 31 ++++--
arch/x86/vdso/vdso2c.h | 180 +++++++++++++++++++++++++++----
arch/x86/vdso/vdso32/vdso-fakesections.c | 1 +
arch/x86/vdso/vdsox32.lds.S | 2 +
8 files changed, 237 insertions(+), 67 deletions(-)
create mode 100644 arch/x86/vdso/vdso32/vdso-fakesections.c
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 3c0809a..2c1ca98 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -11,7 +11,6 @@ VDSO32-$(CONFIG_COMPAT) := y
# files to link into the vdso
vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vdso-fakesections.o
-vobjs-nox32 := vdso-fakesections.o
# files to link into kernel
obj-y += vma.o
@@ -134,7 +133,7 @@ override obj-dirs = $(dir $(obj)) $(obj)/vdso32/
targets += vdso32/vdso32.lds
targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o)
-targets += vdso32/vclock_gettime.o
+targets += vdso32/vclock_gettime.o vdso32/vdso-fakesections.o
$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%)
@@ -155,6 +154,7 @@ $(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
$(obj)/vdso32/vdso32.lds \
$(obj)/vdso32/vclock_gettime.o \
+ $(obj)/vdso32/vdso-fakesections.o \
$(obj)/vdso32/note.o \
$(obj)/vdso32/%.o
$(call if_changed,vdso)
diff --git a/arch/x86/vdso/vdso-fakesections.c b/arch/x86/vdso/vdso-fakesections.c
index cb8a8d7..56927a7 100644
--- a/arch/x86/vdso/vdso-fakesections.c
+++ b/arch/x86/vdso/vdso-fakesections.c
@@ -2,31 +2,23 @@
* Copyright 2014 Andy Lutomirski
* Subject to the GNU Public License, v.2
*
- * Hack to keep broken Go programs working.
- *
- * The Go runtime had a couple of bugs: it would read the section table to try
- * to figure out how many dynamic symbols there were (it shouldn't have looked
- * at the section table at all) and, if there were no SHT_SYNDYM section table
- * entry, it would use an uninitialized value for the number of symbols. As a
- * workaround, we supply a minimal section table. vdso2c will adjust the
- * in-memory image so that "vdso_fake_sections" becomes the section table.
- *
- * The bug was introduced by:
- * https://code.google.com/p/go/source/detail?r=56ea40aac72b (2012-08-31)
- * and is being addressed in the Go runtime in this issue:
- * https://code.google.com/p/go/issues/detail?id=8197
+ * String table for loadable section headers. See vdso2c.h for why
+ * this exists.
*/
-#ifndef __x86_64__
-#error This hack is specific to the 64-bit vDSO
-#endif
-
-#include <linux/elf.h>
-
-extern const __visible struct elf64_shdr vdso_fake_sections[];
-const __visible struct elf64_shdr vdso_fake_sections[] = {
- {
- .sh_type = SHT_DYNSYM,
- .sh_entsize = sizeof(Elf64_Sym),
- }
-};
+const char fake_shstrtab[] __attribute__((section(".fake_shstrtab"))) =
+ ".hash\0"
+ ".dynsym\0"
+ ".dynstr\0"
+ ".gnu.version\0"
+ ".gnu.version_d\0"
+ ".dynamic\0"
+ ".rodata\0"
+ ".fake_shstrtab\0" /* Yay, self-referential code. */
+ ".note\0"
+ ".data\0"
+ ".altinstructions\0"
+ ".altinstr_replacement\0"
+ ".eh_frame_hdr\0"
+ ".eh_frame\0"
+ ".text";
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S
index c84166c..e4cbc21 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/vdso/vdso-layout.lds.S
@@ -6,6 +6,16 @@
* This script controls its layout.
*/
+#if defined(BUILD_VDSO64)
+# define SHDR_SIZE 64
+#elif defined(BUILD_VDSO32) || defined(BUILD_VDSOX32)
+# define SHDR_SIZE 40
+#else
+# error unknown VDSO target
+#endif
+
+#define NUM_FAKE_SHDRS 16
+
SECTIONS
{
. = SIZEOF_HEADERS;
@@ -25,15 +35,29 @@ SECTIONS
.dynamic : { *(.dynamic) } :text :dynamic
- .rodata : { *(.rodata*) } :text
+ .rodata : {
+ *(.rodata*)
+
+ /*
+ * Ideally this would live in a C file, but that won't
+ * work cleanly for x32 until we start building the x32
+ * C code using an x32 toolchain.
+ */
+ VDSO_FAKE_SECTION_TABLE_START = .;
+ . = . + NUM_FAKE_SHDRS * SHDR_SIZE;
+ VDSO_FAKE_SECTION_TABLE_END = .;
+ } :text
+
+ .fake_shstrtab : { *(.fake_shstrtab) } :text
+
.data : {
- *(.data*)
- *(.sdata*)
- *(.got.plt) *(.got)
- *(.gnu.linkonce.d.*)
- *(.bss*)
- *(.dynbss*)
- *(.gnu.linkonce.b.*)
+ *(.data*)
+ *(.sdata*)
+ *(.got.plt) *(.got)
+ *(.gnu.linkonce.d.*)
+ *(.bss*)
+ *(.dynbss*)
+ *(.gnu.linkonce.b.*)
}
.altinstructions : { *(.altinstructions) }
diff --git a/arch/x86/vdso/vdso.lds.S b/arch/x86/vdso/vdso.lds.S
index 75e3404..6807932 100644
--- a/arch/x86/vdso/vdso.lds.S
+++ b/arch/x86/vdso/vdso.lds.S
@@ -6,6 +6,8 @@
* the DSO.
*/
+#define BUILD_VDSO64
+
#include "vdso-layout.lds.S"
/*
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c
index 7343899..238dbe82 100644
--- a/arch/x86/vdso/vdso2c.c
+++ b/arch/x86/vdso/vdso2c.c
@@ -23,6 +23,8 @@ enum {
sym_vvar_page,
sym_hpet_page,
sym_end_mapping,
+ sym_VDSO_FAKE_SECTION_TABLE_START,
+ sym_VDSO_FAKE_SECTION_TABLE_END,
};
const int special_pages[] = {
@@ -30,15 +32,26 @@ const int special_pages[] = {
sym_hpet_page,
};
-char const * const required_syms[] = {
- [sym_vvar_page] = "vvar_page",
- [sym_hpet_page] = "hpet_page",
- [sym_end_mapping] = "end_mapping",
- "VDSO32_NOTE_MASK",
- "VDSO32_SYSENTER_RETURN",
- "__kernel_vsyscall",
- "__kernel_sigreturn",
- "__kernel_rt_sigreturn",
+struct vdso_sym {
+ const char *name;
+ bool export;
+};
+
+struct vdso_sym required_syms[] = {
+ [sym_vvar_page] = {"vvar_page", true},
+ [sym_hpet_page] = {"hpet_page", true},
+ [sym_end_mapping] = {"end_mapping", true},
+ [sym_VDSO_FAKE_SECTION_TABLE_START] = {
+ "VDSO_FAKE_SECTION_TABLE_START", false
+ },
+ [sym_VDSO_FAKE_SECTION_TABLE_END] = {
+ "VDSO_FAKE_SECTION_TABLE_END", false
+ },
+ {"VDSO32_NOTE_MASK", true},
+ {"VDSO32_SYSENTER_RETURN", true},
+ {"__kernel_vsyscall", true},
+ {"__kernel_sigreturn", true},
+ {"__kernel_rt_sigreturn", true},
};
__attribute__((format(printf, 1, 2))) __attribute__((noreturn))
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
index 8e185ce..f01ed4b 100644
--- a/arch/x86/vdso/vdso2c.h
+++ b/arch/x86/vdso/vdso2c.h
@@ -4,6 +4,116 @@
* are built for 32-bit userspace.
*/
+/*
+ * We're writing a section table for a few reasons:
+ *
+ * The Go runtime had a couple of bugs: it would read the section
+ * table to try to figure out how many dynamic symbols there were (it
+ * shouldn't have looked at the section table at all) and, if there
+ * were no SHT_SYNDYM section table entry, it would use an
+ * uninitialized value for the number of symbols. An empty DYNSYM
+ * table would work, but I see no reason not to write a valid one (and
+ * keep full performance for old Go programs). This hack is only
+ * needed on x86_64.
+ *
+ * The bug was introduced on 2012-08-31 by:
+ * https://code.google.com/p/go/source/detail?r=56ea40aac72b
+ * and was fixed on 2014-06-13 by:
+ * https://code.google.com/p/go/source/detail?r=fc1cd5e12595
+ *
+ * Binutils has issues debugging the vDSO: it reads the section table to
+ * find SHT_NOTE; it won't look at PT_NOTE for the in-memory vDSO, which
+ * would break build-id if we removed the section table. Binutils
+ * also requires that shstrndx != 0. See:
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=17064
+ *
+ * elfutils might not look for PT_NOTE if there is a section table at
+ * all. I don't know whether this matters for any practical purpose.
+ *
+ * For simplicity, rather than hacking up a partial section table, we
+ * just write a mostly complete one. We omit non-dynamic symbols,
+ * though, since they're rather large.
+ *
+ * Once binutils gets fixed, we might be able to drop this for all but
+ * the 64-bit vdso, since build-id only works in kernel RPMs, and
+ * systems that update to new enough kernel RPMs will likely update
+ * binutils in sync. build-id has never worked for home-built kernel
+ * RPMs without manual symlinking, and I suspect that no one ever does
+ * that.
+ */
+struct BITSFUNC(fake_sections)
+{
+ ELF(Shdr) *table;
+ unsigned long table_offset;
+ int count, max_count;
+
+ int in_shstrndx;
+ unsigned long shstr_offset;
+ const char *shstrtab;
+ size_t shstrtab_len;
+
+ int out_shstrndx;
+};
+
+static unsigned int BITSFUNC(find_shname)(struct BITSFUNC(fake_sections) *out,
+ const char *name)
+{
+ const char *outname = out->shstrtab;
+ while (outname - out->shstrtab < out->shstrtab_len) {
+ if (!strcmp(name, outname))
+ return (outname - out->shstrtab) + out->shstr_offset;
+ outname += strlen(outname) + 1;
+ }
+
+ if (*name)
+ printf("Warning: could not find output name \"%s\"\n", name);
+ return out->shstr_offset + out->shstrtab_len - 1; /* Use a null. */
+}
+
+static void BITSFUNC(init_sections)(struct BITSFUNC(fake_sections) *out)
+{
+ if (!out->in_shstrndx)
+ fail("didn't find the fake shstrndx\n");
+
+ memset(out->table, 0, out->max_count * sizeof(ELF(Shdr)));
+
+ if (out->max_count < 1)
+ fail("we need at least two fake output sections\n");
+
+ PUT_LE(&out->table[0].sh_type, SHT_NULL);
+ PUT_LE(&out->table[0].sh_name, BITSFUNC(find_shname)(out, ""));
+
+ out->count = 1;
+}
+
+static void BITSFUNC(copy_section)(struct BITSFUNC(fake_sections) *out,
+ int in_idx, const ELF(Shdr) *in,
+ const char *name)
+{
+ uint64_t flags = GET_LE(&in->sh_flags);
+
+ bool copy = flags & SHF_ALLOC;
+
+ if (!copy)
+ return;
+
+ if (out->count >= out->max_count)
+ fail("too many copied sections (max = %d)\n", out->max_count);
+
+ if (in_idx == out->in_shstrndx)
+ out->out_shstrndx = out->count;
+
+ out->table[out->count] = *in;
+ PUT_LE(&out->table[out->count].sh_name,
+ BITSFUNC(find_shname)(out, name));
+
+ /* elfutils requires that a strtab have the correct type. */
+ if (!strcmp(name, ".fake_shstrtab"))
+ PUT_LE(&out->table[out->count].sh_type, SHT_STRTAB);
+
+ out->count++;
+}
+
static void BITSFUNC(go)(void *addr, size_t len,
FILE *outfile, const char *name)
{
@@ -19,7 +129,7 @@ static void BITSFUNC(go)(void *addr, size_t len,
const char *secstrings;
uint64_t syms[NSYMS] = {};
- uint64_t fake_sections_value = 0, fake_sections_size = 0;
+ struct BITSFUNC(fake_sections) fake_sections = {};
ELF(Phdr) *pt = (ELF(Phdr) *)(addr + GET_LE(&hdr->e_phoff));
@@ -89,23 +199,57 @@ static void BITSFUNC(go)(void *addr, size_t len,
GET_LE(&sym->st_name);
for (k = 0; k < NSYMS; k++) {
- if (!strcmp(name, required_syms[k])) {
+ if (!strcmp(name, required_syms[k].name)) {
if (syms[k]) {
fail("duplicate symbol %s\n",
- required_syms[k]);
+ required_syms[k].name);
}
syms[k] = GET_LE(&sym->st_value);
}
}
- if (!strcmp(name, "vdso_fake_sections")) {
- if (fake_sections_value)
- fail("duplicate vdso_fake_sections\n");
- fake_sections_value = GET_LE(&sym->st_value);
- fake_sections_size = GET_LE(&sym->st_size);
+ if (!strcmp(name, "fake_shstrtab")) {
+ ELF(Shdr) *sh;
+
+ fake_sections.in_shstrndx = GET_LE(&sym->st_shndx);
+ fake_sections.shstrtab = addr + GET_LE(&sym->st_value);
+ fake_sections.shstrtab_len = GET_LE(&sym->st_size);
+ sh = addr + GET_LE(&hdr->e_shoff) +
+ GET_LE(&hdr->e_shentsize) *
+ fake_sections.in_shstrndx;
+ fake_sections.shstr_offset = GET_LE(&sym->st_value) -
+ GET_LE(&sh->sh_addr);
}
}
+ /* Build the output section table. */
+ if (!syms[sym_VDSO_FAKE_SECTION_TABLE_START] ||
+ !syms[sym_VDSO_FAKE_SECTION_TABLE_END])
+ fail("couldn't find fake section table\n");
+ if ((syms[sym_VDSO_FAKE_SECTION_TABLE_END] -
+ syms[sym_VDSO_FAKE_SECTION_TABLE_START]) % sizeof(ELF(Shdr)))
+ fail("fake section table size isn't a multiple of sizeof(Shdr)\n");
+ fake_sections.table = addr + syms[sym_VDSO_FAKE_SECTION_TABLE_START];
+ fake_sections.table_offset = syms[sym_VDSO_FAKE_SECTION_TABLE_START];
+ fake_sections.max_count = (syms[sym_VDSO_FAKE_SECTION_TABLE_END] -
+ syms[sym_VDSO_FAKE_SECTION_TABLE_START]) /
+ sizeof(ELF(Shdr));
+
+ BITSFUNC(init_sections)(&fake_sections);
+ for (i = 0; i < GET_LE(&hdr->e_shnum); i++) {
+ ELF(Shdr) *sh = addr + GET_LE(&hdr->e_shoff) +
+ GET_LE(&hdr->e_shentsize) * i;
+ BITSFUNC(copy_section)(&fake_sections, i, sh,
+ secstrings + GET_LE(&sh->sh_name));
+ }
+ if (!fake_sections.out_shstrndx)
+ fail("didn't generate shstrndx?!?\n");
+
+ PUT_LE(&hdr->e_shoff, fake_sections.table_offset);
+ PUT_LE(&hdr->e_shentsize, sizeof(ELF(Shdr)));
+ PUT_LE(&hdr->e_shnum, fake_sections.count);
+ PUT_LE(&hdr->e_shstrndx, fake_sections.out_shstrndx);
+
/* Validate mapping addresses. */
for (i = 0; i < sizeof(special_pages) / sizeof(special_pages[0]); i++) {
if (!syms[i])
@@ -113,25 +257,17 @@ static void BITSFUNC(go)(void *addr, size_t len,
if (syms[i] % 4096)
fail("%s must be a multiple of 4096\n",
- required_syms[i]);
+ required_syms[i].name);
if (syms[i] < data_size)
fail("%s must be after the text mapping\n",
- required_syms[i]);
+ required_syms[i].name);
if (syms[sym_end_mapping] < syms[i] + 4096)
- fail("%s overruns end_mapping\n", required_syms[i]);
+ fail("%s overruns end_mapping\n",
+ required_syms[i].name);
}
if (syms[sym_end_mapping] % 4096)
fail("end_mapping must be a multiple of 4096\n");
- /* Remove sections or use fakes */
- if (fake_sections_size % sizeof(ELF(Shdr)))
- fail("vdso_fake_sections size is not a multiple of %ld\n",
- (long)sizeof(ELF(Shdr)));
- PUT_LE(&hdr->e_shoff, fake_sections_value);
- PUT_LE(&hdr->e_shentsize, fake_sections_value ? sizeof(ELF(Shdr)) : 0);
- PUT_LE(&hdr->e_shnum, fake_sections_size / sizeof(ELF(Shdr)));
- PUT_LE(&hdr->e_shstrndx, SHN_UNDEF);
-
if (!name) {
fwrite(addr, load_size, 1, outfile);
return;
@@ -169,9 +305,9 @@ static void BITSFUNC(go)(void *addr, size_t len,
(unsigned long)GET_LE(&alt_sec->sh_size));
}
for (i = 0; i < NSYMS; i++) {
- if (syms[i])
+ if (required_syms[i].export && syms[i])
fprintf(outfile, "\t.sym_%s = 0x%" PRIx64 ",\n",
- required_syms[i], syms[i]);
+ required_syms[i].name, syms[i]);
}
fprintf(outfile, "};\n");
}
diff --git a/arch/x86/vdso/vdso32/vdso-fakesections.c b/arch/x86/vdso/vdso32/vdso-fakesections.c
new file mode 100644
index 0000000..541468e
--- /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 46b991b..697c11e 100644
--- a/arch/x86/vdso/vdsox32.lds.S
+++ b/arch/x86/vdso/vdsox32.lds.S
@@ -6,6 +6,8 @@
* the DSO.
*/
+#define BUILD_VDSOX32
+
#include "vdso-layout.lds.S"
/*
--
1.9.3
Rather than using a separate macro for each replacement, use generic
macros.
Signed-off-by: Andy Lutomirski <[email protected]>
---
arch/x86/vdso/vdso2c.c | 42 +++++++++++++-----------------------------
arch/x86/vdso/vdso2c.h | 23 ++++++++++++-----------
2 files changed, 25 insertions(+), 40 deletions(-)
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c
index 7a6bf50..7343899 100644
--- a/arch/x86/vdso/vdso2c.c
+++ b/arch/x86/vdso/vdso2c.c
@@ -83,37 +83,21 @@ extern void bad_put_le(void);
#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))
-#define BITS 64
-#define GOFUNC go64
-#define Elf_Ehdr Elf64_Ehdr
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Phdr Elf64_Phdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Dyn Elf64_Dyn
+#define BITSFUNC3(name, bits) name##bits
+#define BITSFUNC2(name, bits) BITSFUNC3(name, bits)
+#define BITSFUNC(name) BITSFUNC2(name, ELF_BITS)
+
+#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
+#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
+#define ELF(x) ELF_BITS_XFORM(ELF_BITS, x)
+
+#define ELF_BITS 64
#include "vdso2c.h"
-#undef BITS
-#undef GOFUNC
-#undef Elf_Ehdr
-#undef Elf_Shdr
-#undef Elf_Phdr
-#undef Elf_Sym
-#undef Elf_Dyn
-
-#define BITS 32
-#define GOFUNC go32
-#define Elf_Ehdr Elf32_Ehdr
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Phdr Elf32_Phdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Dyn Elf32_Dyn
+#undef ELF_BITS
+
+#define ELF_BITS 32
#include "vdso2c.h"
-#undef BITS
-#undef GOFUNC
-#undef Elf_Ehdr
-#undef Elf_Shdr
-#undef Elf_Phdr
-#undef Elf_Sym
-#undef Elf_Dyn
+#undef ELF_BITS
static void go(void *addr, size_t len, FILE *outfile, const char *name)
{
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
index c6eefaf..8e185ce 100644
--- a/arch/x86/vdso/vdso2c.h
+++ b/arch/x86/vdso/vdso2c.h
@@ -4,23 +4,24 @@
* are built for 32-bit userspace.
*/
-static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
+static void BITSFUNC(go)(void *addr, size_t len,
+ FILE *outfile, const char *name)
{
int found_load = 0;
unsigned long load_size = -1; /* Work around bogus warning */
unsigned long data_size;
- Elf_Ehdr *hdr = (Elf_Ehdr *)addr;
+ ELF(Ehdr) *hdr = (ELF(Ehdr) *)addr;
int i;
unsigned long j;
- Elf_Shdr *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr,
+ ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr,
*alt_sec = NULL;
- Elf_Dyn *dyn = 0, *dyn_end = 0;
+ ELF(Dyn) *dyn = 0, *dyn_end = 0;
const char *secstrings;
uint64_t syms[NSYMS] = {};
uint64_t fake_sections_value = 0, fake_sections_size = 0;
- Elf_Phdr *pt = (Elf_Phdr *)(addr + GET_LE(&hdr->e_phoff));
+ ELF(Phdr) *pt = (ELF(Phdr) *)(addr + GET_LE(&hdr->e_phoff));
/* Walk the segment table. */
for (i = 0; i < GET_LE(&hdr->e_phnum); i++) {
@@ -61,7 +62,7 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
GET_LE(&hdr->e_shentsize)*GET_LE(&hdr->e_shstrndx);
secstrings = addr + GET_LE(&secstrings_hdr->sh_offset);
for (i = 0; i < GET_LE(&hdr->e_shnum); i++) {
- Elf_Shdr *sh = addr + GET_LE(&hdr->e_shoff) +
+ ELF(Shdr) *sh = addr + GET_LE(&hdr->e_shoff) +
GET_LE(&hdr->e_shentsize) * i;
if (GET_LE(&sh->sh_type) == SHT_SYMTAB)
symtab_hdr = sh;
@@ -82,7 +83,7 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
i < GET_LE(&symtab_hdr->sh_size) / GET_LE(&symtab_hdr->sh_entsize);
i++) {
int k;
- Elf_Sym *sym = addr + GET_LE(&symtab_hdr->sh_offset) +
+ ELF(Sym) *sym = addr + GET_LE(&symtab_hdr->sh_offset) +
GET_LE(&symtab_hdr->sh_entsize) * i;
const char *name = addr + GET_LE(&strtab_hdr->sh_offset) +
GET_LE(&sym->st_name);
@@ -123,12 +124,12 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
fail("end_mapping must be a multiple of 4096\n");
/* Remove sections or use fakes */
- if (fake_sections_size % sizeof(Elf_Shdr))
+ if (fake_sections_size % sizeof(ELF(Shdr)))
fail("vdso_fake_sections size is not a multiple of %ld\n",
- (long)sizeof(Elf_Shdr));
+ (long)sizeof(ELF(Shdr)));
PUT_LE(&hdr->e_shoff, fake_sections_value);
- PUT_LE(&hdr->e_shentsize, fake_sections_value ? sizeof(Elf_Shdr) : 0);
- PUT_LE(&hdr->e_shnum, fake_sections_size / sizeof(Elf_Shdr));
+ PUT_LE(&hdr->e_shentsize, fake_sections_value ? sizeof(ELF(Shdr)) : 0);
+ PUT_LE(&hdr->e_shnum, fake_sections_size / sizeof(ELF(Shdr)));
PUT_LE(&hdr->e_shstrndx, SHN_UNDEF);
if (!name) {
--
1.9.3
With this change, doing 'make vdso_install' and telling gdb:
set debug-file-directory /lib/modules/KVER/vdso
will enable vdso debugging with symbols. This is useful for
testing, but kernel RPM builds will probably want to manually delete
these symlinks or otherwise do something sensible when they strip
the vdso/*.so files.
If ld does not support --build-id, then the symlinks will not be
created.
Note that kernel packagers that use vdso_install may need to adjust
their packaging scripts to accomdate this change. For example,
Fedora's scripts create build-id symlinks themselves in a different
location, so the spec should probably be updated to remove the
symlinks created by make vdso_install.
Signed-off-by: Andy Lutomirski <[email protected]>
---
arch/x86/vdso/Makefile | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 2c1ca98..68a15c4 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -169,14 +169,24 @@ quiet_cmd_vdso = VDSO $@
sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
- -Wl,-Bsymbolic $(LTO_CFLAGS)
+ $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic $(LTO_CFLAGS)
GCOV_PROFILE := n
#
-# Install the unstripped copies of vdso*.so.
+# Install the unstripped copies of vdso*.so. If our toolchain supports
+# build-id, install .build-id links as well.
#
quiet_cmd_vdso_install = INSTALL $(@:install_%=%)
- cmd_vdso_install = cp $< $(MODLIB)/vdso/$(@:install_%=%)
+define cmd_vdso_install
+ cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \
+ if readelf -n $< |grep -q 'Build ID'; then \
+ buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \
+ first=`echo $$buildid | cut -b-2`; \
+ last=`echo $$buildid | cut -b3-`; \
+ mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \
+ ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \
+ fi
+endef
vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%)
--
1.9.3
.data doesn't need to be separate from .rodata: they're both readonly.
.altinstructions and .altinstr_replacement aren't needed by anything
except vdso2c; strip them from the final image.
While we're at it, rather than aligning the actual executable text,
just shove some unused-at-runtime data in between real data and
text.
My vdso image is still above 4k, but I'm disinclined to try to
trim it harder for 3.16. For future trimming, I suspect that these
sections could be moved to later in the file and dropped from
the in-memory image:
.gnu.version and .gnu.version_d (this may lose versions in gdb)
.eh_frame (should be harmless)
.eh_frame_hdr (I'm not really sure)
.hash (AFAIK nothing needs this section header)
Signed-off-by: Andy Lutomirski <[email protected]>
---
arch/x86/vdso/vdso-fakesections.c | 3 ---
arch/x86/vdso/vdso-layout.lds.S | 43 +++++++++++++++++++++------------------
arch/x86/vdso/vdso2c.h | 4 +++-
3 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/arch/x86/vdso/vdso-fakesections.c b/arch/x86/vdso/vdso-fakesections.c
index 56927a7..aa5fbfa 100644
--- a/arch/x86/vdso/vdso-fakesections.c
+++ b/arch/x86/vdso/vdso-fakesections.c
@@ -16,9 +16,6 @@ const char fake_shstrtab[] __attribute__((section(".fake_shstrtab"))) =
".rodata\0"
".fake_shstrtab\0" /* Yay, self-referential code. */
".note\0"
- ".data\0"
- ".altinstructions\0"
- ".altinstr_replacement\0"
".eh_frame_hdr\0"
".eh_frame\0"
".text";
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S
index e4cbc21..9197544 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/vdso/vdso-layout.lds.S
@@ -14,7 +14,7 @@
# error unknown VDSO target
#endif
-#define NUM_FAKE_SHDRS 16
+#define NUM_FAKE_SHDRS 13
SECTIONS
{
@@ -28,15 +28,17 @@ SECTIONS
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
- .note : { *(.note.*) } :text :note
-
- .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
- .eh_frame : { KEEP (*(.eh_frame)) } :text
-
.dynamic : { *(.dynamic) } :text :dynamic
.rodata : {
*(.rodata*)
+ *(.data*)
+ *(.sdata*)
+ *(.got.plt) *(.got)
+ *(.gnu.linkonce.d.*)
+ *(.bss*)
+ *(.dynbss*)
+ *(.gnu.linkonce.b.*)
/*
* Ideally this would live in a C file, but that won't
@@ -50,28 +52,29 @@ SECTIONS
.fake_shstrtab : { *(.fake_shstrtab) } :text
- .data : {
- *(.data*)
- *(.sdata*)
- *(.got.plt) *(.got)
- *(.gnu.linkonce.d.*)
- *(.bss*)
- *(.dynbss*)
- *(.gnu.linkonce.b.*)
- }
- .altinstructions : { *(.altinstructions) }
- .altinstr_replacement : { *(.altinstr_replacement) }
+ .note : { *(.note.*) } :text :note
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
/*
- * Align the actual code well away from the non-instruction data.
- * This is the best thing for the I-cache.
+ * Text is well-separated from actual data: there's plenty of
+ * stuff that isn't used at runtime in between.
*/
- . = ALIGN(0x100);
.text : { *(.text*) } :text =0x90909090,
/*
+ * At the end so that eu-elflint stays happy when vdso2c strips
+ * these. A better implementation would avoid allocating space
+ * for these.
+ */
+ .altinstructions : { *(.altinstructions) } :text
+ .altinstr_replacement : { *(.altinstr_replacement) } :text
+
+ /*
* The remainder of the vDSO consists of special pages that are
* shared between the kernel and userspace. It needs to be at the
* end so that it doesn't overlap the mapping of the actual
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
index f01ed4b..f42e2dd 100644
--- a/arch/x86/vdso/vdso2c.h
+++ b/arch/x86/vdso/vdso2c.h
@@ -92,7 +92,9 @@ static void BITSFUNC(copy_section)(struct BITSFUNC(fake_sections) *out,
{
uint64_t flags = GET_LE(&in->sh_flags);
- bool copy = flags & SHF_ALLOC;
+ bool copy = flags & SHF_ALLOC &&
+ strcmp(name, ".altinstructions") &&
+ strcmp(name, ".altinstr_replacement");
if (!copy)
return;
--
1.9.3
Commit-ID: dda1e95cee38b416b23f751cac65421d781e3c10
Gitweb: http://git.kernel.org/tip/dda1e95cee38b416b23f751cac65421d781e3c10
Author: Andy Lutomirski <[email protected]>
AuthorDate: Fri, 20 Jun 2014 12:20:44 -0700
Committer: H. Peter Anvin <[email protected]>
CommitDate: Fri, 20 Jun 2014 13:18:49 -0700
x86/vdso: Create .build-id links for unstripped vdso files
With this change, doing 'make vdso_install' and telling gdb:
set debug-file-directory /lib/modules/KVER/vdso
will enable vdso debugging with symbols. This is useful for
testing, but kernel RPM builds will probably want to manually delete
these symlinks or otherwise do something sensible when they strip
the vdso/*.so files.
If ld does not support --build-id, then the symlinks will not be
created.
Note that kernel packagers that use vdso_install may need to adjust
their packaging scripts to accomdate this change. For example,
Fedora's scripts create build-id symlinks themselves in a different
location, so the spec should probably be updated to remove the
symlinks created by make vdso_install.
Signed-off-by: Andy Lutomirski <[email protected]>
Link: http://lkml.kernel.org/r/a424b189ce3ced85fe1e82d032a20e765e0fe0d3.1403291930.git.luto@amacapital.net
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/vdso/Makefile | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 2c1ca98..68a15c4 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -169,14 +169,24 @@ quiet_cmd_vdso = VDSO $@
sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
- -Wl,-Bsymbolic $(LTO_CFLAGS)
+ $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic $(LTO_CFLAGS)
GCOV_PROFILE := n
#
-# Install the unstripped copies of vdso*.so.
+# Install the unstripped copies of vdso*.so. If our toolchain supports
+# build-id, install .build-id links as well.
#
quiet_cmd_vdso_install = INSTALL $(@:install_%=%)
- cmd_vdso_install = cp $< $(MODLIB)/vdso/$(@:install_%=%)
+define cmd_vdso_install
+ cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \
+ if readelf -n $< |grep -q 'Build ID'; then \
+ buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \
+ first=`echo $$buildid | cut -b-2`; \
+ last=`echo $$buildid | cut -b3-`; \
+ mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \
+ ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \
+ fi
+endef
vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%)
Hi Andy,
On Sat, Jun 21, 2014 at 4:23 AM Andy Lutomirski <[email protected]> wrote:
>
> With this change, doing 'make vdso_install' and telling gdb:
>
> set debug-file-directory /lib/modules/KVER/vdso
>
> will enable vdso debugging with symbols. This is useful for
> testing, but kernel RPM builds will probably want to manually delete
> these symlinks or otherwise do something sensible when they strip
> the vdso/*.so files.
>
> If ld does not support --build-id, then the symlinks will not be
> created.
>
> Note that kernel packagers that use vdso_install may need to adjust
> their packaging scripts to accomdate this change. For example,
> Fedora's scripts create build-id symlinks themselves in a different
> location, so the spec should probably be updated to remove the
> symlinks created by make vdso_install.
>
> Signed-off-by: Andy Lutomirski <[email protected]>
> ---
I was looking into this, but
I am not familiar enough with this area.
Could you tell me how it works?
I use Ubuntu 18.04 LTS.
Luckily, it has build-id symlinks by default,
so I should be able to test it easily.
masahiro@pug:~$ uname -r
4.15.0-47-generic
masahiro@pug:~$ cd /lib/modules/4.15.0-47-generic/vdso/
masahiro@pug:/lib/modules/4.15.0-47-generic/vdso$ file vdso64.so
vdso64.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV),
dynamically linked,
BuildID[sha1]=d742540fb9ded5c3650dbe9ae20c0f39e386464c, with
debug_info, not stripped
masahiro@pug:/lib/modules/4.15.0-47-generic/vdso$ ls -l
.build-id/d7/42540fb9ded5c3650dbe9ae20c0f39e386464c.debug
lrwxrwxrwx 1 root root 15 Mar 13 13:37
.build-id/d7/42540fb9ded5c3650dbe9ae20c0f39e386464c.debug ->
../../vdso64.so
I dumped the vdso embedded in the kernel,
and I confirmed its build-id matches
to the one of unstripped vdso.
So, I expect the vdso with symbol info will be automatically loaded
by setting debug-file-directory to /lib/modules/4.15.0-47-generic/vdso.
Am I right?
If it works as expected, how should it look like?
I started gdb like this:
$ gdb date
Then, I did:
(gdb) set debug-file-directory
/usr/lib/debug:/lib/modules/4.15.0-47-generic/vdso
(gdb) show debug-file-directory
The directory where separate debug symbols are searched for is
"/usr/lib/debug:/lib/modules/4.15.0-47-generic/vdso".
(gdb) run
The list of shared library looks like follows:
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x00007ffff7dd5f10 0x00007ffff7df4b20 Yes /lib64/ld-linux-x86-64.so.2
0x00007ffff7a052d0 0x00007ffff7b7dc3c Yes
/lib/x86_64-linux-gnu/libc.so.6
No linux-vdso.so.1
The first two shared objects shows "Yes" because debug info
is available under /usr/lib/debug/lib/x86_64-linux-gnu/
and associated by .gnu_debuglink.
linux-vdso.so.1 shows "No".
Does it mean no symbol was included ?
Thank you.
Masahiro Yamada
> arch/x86/vdso/Makefile | 16 +++++++++++++---
> 1 file changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
> index 2c1ca98..68a15c4 100644
> --- a/arch/x86/vdso/Makefile
> +++ b/arch/x86/vdso/Makefile
> @@ -169,14 +169,24 @@ quiet_cmd_vdso = VDSO $@
> sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
>
> VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
> - -Wl,-Bsymbolic $(LTO_CFLAGS)
> + $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic $(LTO_CFLAGS)
> GCOV_PROFILE := n
>
> #
> -# Install the unstripped copies of vdso*.so.
> +# Install the unstripped copies of vdso*.so. If our toolchain supports
> +# build-id, install .build-id links as well.
> #
> quiet_cmd_vdso_install = INSTALL $(@:install_%=%)
> - cmd_vdso_install = cp $< $(MODLIB)/vdso/$(@:install_%=%)
> +define cmd_vdso_install
> + cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \
> + if readelf -n $< |grep -q 'Build ID'; then \
> + buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \
> + first=`echo $$buildid | cut -b-2`; \
> + last=`echo $$buildid | cut -b3-`; \
> + mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \
> + ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \
> + fi
> +endef
>
> vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%)
>
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
Best Regards
Masahiro Yamada
On Thu, Apr 25, 2019 at 4:42 AM Masahiro Yamada
<[email protected]> wrote:
>
> Hi Andy,
>
> On Sat, Jun 21, 2014 at 4:23 AM Andy Lutomirski <[email protected]> wrote:
> >
> > With this change, doing 'make vdso_install' and telling gdb:
> >
> > set debug-file-directory /lib/modules/KVER/vdso
> >
> > will enable vdso debugging with symbols. This is useful for
> > testing, but kernel RPM builds will probably want to manually delete
> > these symlinks or otherwise do something sensible when they strip
> > the vdso/*.so files.
> >
> > If ld does not support --build-id, then the symlinks will not be
> > created.
> >
> > Note that kernel packagers that use vdso_install may need to adjust
> > their packaging scripts to accomdate this change. For example,
> > Fedora's scripts create build-id symlinks themselves in a different
> > location, so the spec should probably be updated to remove the
> > symlinks created by make vdso_install.
> >
> > Signed-off-by: Andy Lutomirski <[email protected]>
> > ---
>
> I was looking into this, but
> I am not familiar enough with this area.
>
>
> Could you tell me how it works?
>
>
> I use Ubuntu 18.04 LTS.
> Luckily, it has build-id symlinks by default,
> so I should be able to test it easily.
>
>
>
> masahiro@pug:~$ uname -r
> 4.15.0-47-generic
> masahiro@pug:~$ cd /lib/modules/4.15.0-47-generic/vdso/
> masahiro@pug:/lib/modules/4.15.0-47-generic/vdso$ file vdso64.so
> vdso64.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV),
> dynamically linked,
> BuildID[sha1]=d742540fb9ded5c3650dbe9ae20c0f39e386464c, with
> debug_info, not stripped
> masahiro@pug:/lib/modules/4.15.0-47-generic/vdso$ ls -l
> .build-id/d7/42540fb9ded5c3650dbe9ae20c0f39e386464c.debug
> lrwxrwxrwx 1 root root 15 Mar 13 13:37
> .build-id/d7/42540fb9ded5c3650dbe9ae20c0f39e386464c.debug ->
> ../../vdso64.so
>
>
> I dumped the vdso embedded in the kernel,
> and I confirmed its build-id matches
> to the one of unstripped vdso.
>
>
> So, I expect the vdso with symbol info will be automatically loaded
> by setting debug-file-directory to /lib/modules/4.15.0-47-generic/vdso.
> Am I right?
>
> If it works as expected, how should it look like?
>
> I started gdb like this:
>
> $ gdb date
>
> Then, I did:
>
> (gdb) set debug-file-directory
> /usr/lib/debug:/lib/modules/4.15.0-47-generic/vdso
> (gdb) show debug-file-directory
> The directory where separate debug symbols are searched for is
> "/usr/lib/debug:/lib/modules/4.15.0-47-generic/vdso".
> (gdb) run
>
>
> The list of shared library looks like follows:
>
>
> (gdb) info sharedlibrary
> From To Syms Read Shared Object Library
> 0x00007ffff7dd5f10 0x00007ffff7df4b20 Yes /lib64/ld-linux-x86-64.so.2
> 0x00007ffff7a052d0 0x00007ffff7b7dc3c Yes
> /lib/x86_64-linux-gnu/libc.so.6
> No linux-vdso.so.1
>
>
>
> The first two shared objects shows "Yes" because debug info
> is available under /usr/lib/debug/lib/x86_64-linux-gnu/
> and associated by .gnu_debuglink.
>
>
> linux-vdso.so.1 shows "No".
> Does it mean no symbol was included ?
>
It's been a long time since I've looked at this, and I don't remember
all the details. I think your best bet may be to run gdb under strace
and to try to figure out what it's doing.